import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from datetime import datetime
from datetime import date
from dateutil.relativedelta import relativedelta
from datetime import timedelta
import plotly.graph_objects as go
from plotly.subplots import make_subplots
#pip install pykalman
from pykalman import KalmanFilter
#pip install quantstats
import quantstats as qs
Futures_Data = pd.read_excel('Futures_Data.xlsx')
Futures_Data.index = pd.to_datetime(Futures_Data.index)
Futures_orig = Futures_Data.set_index('Date')
beginning_headers = ['USD Future',
'EUR Future (USD)',
'JPY Future (USD)',
'GBP Future (USD)',
'GBP Future (EUR)',
'CAD Future (USD)',
'CHF Future (USD)',
'S&P 500',
'Nasdaq 100',
'DJIA',
'Russell 2000',
'S&P 400',
'S&P Canada 60',
'FTSE 100',
'DAX',
'SMI',
'CAC - 40',
'IBEX 35',
'MIB 30',
'OMX',
'Euro Stoxx 50',
'SPI 200',
'Nikkei 225',
'Hang Seng Index',
'US MSCI EAFE',
'US 2-year',
'US 5-year',
'US 10-year',
'US Ultra 10-year',
'US 30-year',
'Short Gilt (2 year)',
'Medium Gilt (5 year)',
'Long Gilt (10 year)',
'Euro-Schatz-Futures (2 year)',
'Euro-Bobl-Future (5 year)',
'Euro-Bund-Future (10 year)',
'Euro-Buxl-Future (30 year)',
'Brent Crude Oil',
'WTI Crude Oil',
'Heating Oil',
'RBOB Gasoline',
'Natural Gas',
'Gold',
'Silver',
'Platinum',
'Palladium',
'Copper',
'Nickel',
'Zinc',
'Lean hogs',
'Live cattle',
'Feeder cattle',
'Wheat',
'Corn',
'Oat',
'Soybeans',
'Soybean oil',
'Frozen orange juice',
'Cocoa',
'Coffee',
'Sugar No.11',
'Cotton No.2'
]
# Set the new headers
Futures_orig.columns = beginning_headers
Futures_orig
| USD Future | EUR Future (USD) | JPY Future (USD) | GBP Future (USD) | GBP Future (EUR) | CAD Future (USD) | CHF Future (USD) | S&P 500 | Nasdaq 100 | DJIA | ... | Wheat | Corn | Oat | Soybeans | Soybean oil | Frozen orange juice | Cocoa | Coffee | Sugar No.11 | Cotton No.2 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Date | |||||||||||||||||||||
| 1999-01-01 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| 1999-01-04 | 96.398 | 1.44314 | 157.312 | 153.46 | NaN | 0.646 | 115.328 | 1405.44 | NaN | NaN | ... | 93.92159 | 19.15196 | 2.16665 | 2.94494 | 0.47548 | 1.93386 | 4011.0 | 29.62163 | 0.12271 | 3.47810 |
| 1999-01-05 | 96.449 | 1.43755 | 158.465 | 153.27 | NaN | 0.651 | 115.015 | 1419.31 | NaN | NaN | ... | 94.34238 | 19.37492 | 2.19184 | 2.97325 | 0.48036 | 1.97721 | 4037.0 | 28.75183 | 0.13112 | 3.54881 |
| 1999-01-06 | 97.669 | 1.41590 | 155.846 | 153.27 | NaN | 0.653 | 112.996 | 1449.89 | NaN | NaN | ... | 96.78300 | 19.95461 | 2.26239 | 2.99078 | 0.48483 | 1.92255 | 4026.0 | 28.38941 | 0.13187 | 3.53349 |
| 1999-01-07 | 96.801 | 1.42891 | 158.709 | 152.94 | NaN | 0.652 | 114.405 | 1447.06 | NaN | NaN | ... | 96.78300 | 19.59788 | 2.22712 | 2.95842 | 0.48199 | 1.88296 | 4026.0 | 28.66727 | 0.13202 | 3.46691 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2023-12-25 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| 2023-12-26 | 101.104 | 1.10840 | 71.135 | 127.30 | 0.87070 | 0.759 | 118.205 | 4825.00 | 17083.50 | 37894.0 | ... | 6.36250 | 4.80250 | 3.68250 | 13.19000 | 0.48510 | 3.26350 | 4283.0 | 1.94350 | 0.20530 | 0.80050 |
| 2023-12-27 | 100.654 | 1.11385 | 71.420 | 128.00 | 0.87020 | 0.758 | 119.600 | 4833.50 | 17113.25 | 38006.0 | ... | 6.23000 | 4.76500 | 3.73250 | 13.20500 | 0.48660 | 3.25600 | 4280.0 | 1.97750 | 0.20600 | 0.80530 |
| 2023-12-28 | 100.913 | 1.11000 | 71.550 | 127.32 | 0.87180 | 0.757 | 119.500 | 4832.25 | 17090.50 | 38029.0 | ... | 6.31500 | 4.74250 | 3.87250 | 13.12000 | 0.47980 | 3.30200 | 4256.0 | 1.98000 | 0.21760 | 0.80950 |
| 2023-12-29 | 101.029 | 1.10750 | 71.760 | 127.51 | 0.86855 | 0.756 | 119.800 | 4820.00 | 17023.50 | 38012.0 | ... | 6.28000 | 4.71250 | 3.85750 | 12.98000 | 0.48180 | 3.20200 | 4196.0 | 1.88300 | 0.20580 | 0.81000 |
6521 rows × 62 columns
Futures_orig.info()
<class 'pandas.core.frame.DataFrame'> DatetimeIndex: 6521 entries, 1999-01-01 to 2023-12-29 Data columns (total 62 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 USD Future 6446 non-null float64 1 EUR Future (USD) 6342 non-null float64 2 JPY Future (USD) 6343 non-null float64 3 GBP Future (USD) 6343 non-null float64 4 GBP Future (EUR) 6050 non-null float64 5 CAD Future (USD) 6342 non-null float64 6 CHF Future (USD) 6345 non-null float64 7 S&P 500 6340 non-null float64 8 Nasdaq 100 6226 non-null float64 9 DJIA 5484 non-null float64 10 Russell 2000 1633 non-null float64 11 S&P 400 5547 non-null float64 12 S&P Canada 60 6107 non-null float64 13 FTSE 100 6406 non-null float64 14 DAX 6368 non-null float64 15 SMI 6354 non-null float64 16 CAC - 40 6415 non-null float64 17 IBEX 35 6359 non-null float64 18 MIB 30 5027 non-null float64 19 OMX 4749 non-null float64 20 Euro Stoxx 50 6368 non-null float64 21 SPI 200 6074 non-null float64 22 Nikkei 225 6129 non-null float64 23 Hang Seng Index 6191 non-null float64 24 US MSCI EAFE 3690 non-null float64 25 US 2-year 6297 non-null float64 26 US 5-year 6294 non-null float64 27 US 10-year 6289 non-null float64 28 US Ultra 10-year 2009 non-null float64 29 US 30-year 3524 non-null float64 30 Short Gilt (2 year) 3633 non-null float64 31 Medium Gilt (5 year) 3633 non-null float64 32 Long Gilt (10 year) 6410 non-null float64 33 Euro-Schatz-Futures (2 year) 6372 non-null float64 34 Euro-Bobl-Future (5 year) 6370 non-null float64 35 Euro-Bund-Future (10 year) 6371 non-null float64 36 Euro-Buxl-Future (30 year) 6345 non-null float64 37 Brent Crude Oil 6414 non-null float64 38 WTI Crude Oil 6242 non-null float64 39 Heating Oil 6241 non-null float64 40 RBOB Gasoline 4563 non-null float64 41 Natural Gas 6280 non-null float64 42 Gold 6282 non-null float64 43 Silver 6281 non-null float64 44 Platinum 6280 non-null float64 45 Palladium 6279 non-null float64 46 Copper 6281 non-null float64 47 Nickel 6290 non-null float64 48 Zinc 6308 non-null float64 49 Lean hogs 6301 non-null float64 50 Live cattle 6300 non-null float64 51 Feeder cattle 6298 non-null float64 52 Wheat 6298 non-null float64 53 Corn 6297 non-null float64 54 Oat 6298 non-null float64 55 Soybeans 6296 non-null float64 56 Soybean oil 6299 non-null float64 57 Frozen orange juice 6315 non-null float64 58 Cocoa 6271 non-null float64 59 Coffee 6270 non-null float64 60 Sugar No.11 6270 non-null float64 61 Cotton No.2 6309 non-null float64 dtypes: float64(62) memory usage: 3.1 MB
Futures_orig.describe()
| USD Future | EUR Future (USD) | JPY Future (USD) | GBP Future (USD) | GBP Future (EUR) | CAD Future (USD) | CHF Future (USD) | S&P 500 | Nasdaq 100 | DJIA | ... | Wheat | Corn | Oat | Soybeans | Soybean oil | Frozen orange juice | Cocoa | Coffee | Sugar No.11 | Cotton No.2 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| count | 6446.000000 | 6342.000000 | 6343.000000 | 6343.000000 | 6050.000000 | 6342.000000 | 6345.000000 | 6340.000000 | 6226.000000 | 5484.000000 | ... | 6298.000000 | 6297.000000 | 6298.000000 | 6296.000000 | 6299.000000 | 6315.000000 | 6271.000000 | 6270.000000 | 6270.000000 | 6309.000000 |
| mean | 92.352662 | 1.365555 | 119.767115 | 156.222932 | 0.879098 | 0.813842 | 115.315977 | 1975.638863 | 5066.023518 | 17312.395881 | ... | 28.505759 | 6.873685 | 3.009682 | 5.963804 | 0.338447 | 1.447795 | 3074.741030 | 5.425810 | 0.214540 | 1.130652 |
| std | 12.856225 | 0.205537 | 21.178401 | 23.028406 | 0.069735 | 0.115822 | 14.324638 | 1118.152745 | 4315.944208 | 9269.738989 | ... | 19.892358 | 3.630506 | 1.023585 | 2.996857 | 0.118826 | 0.454977 | 682.314146 | 5.211750 | 0.090641 | 0.675171 |
| min | 72.249000 | 0.967680 | 67.310000 | 107.610000 | 0.749890 | 0.605000 | 79.487000 | 618.060000 | 1005.090000 | 5608.210000 | ... | 5.610000 | 2.035280 | 1.279350 | 1.858690 | 0.147050 | 0.665410 | 1434.000000 | 1.044610 | 0.069590 | 0.390200 |
| 25% | 82.774250 | 1.211080 | 103.997000 | 135.690000 | 0.811760 | 0.745000 | 107.990000 | 1179.110000 | 1935.532500 | 9756.257500 | ... | 9.719905 | 4.374680 | 2.178068 | 3.212427 | 0.239830 | 1.108480 | 2598.000000 | 2.200015 | 0.151930 | 0.758490 |
| 50% | 90.308500 | 1.336260 | 118.937000 | 153.900000 | 0.883755 | 0.794000 | 115.446000 | 1449.085000 | 3066.910000 | 13125.990000 | ... | 24.412540 | 6.035560 | 2.802790 | 5.807535 | 0.320440 | 1.432480 | 2945.000000 | 4.467575 | 0.197170 | 0.907400 |
| 75% | 98.711000 | 1.540402 | 134.561500 | 171.480000 | 0.938488 | 0.916000 | 123.663000 | 2578.885000 | 6705.342500 | 25092.237500 | ... | 43.393873 | 8.457120 | 3.716982 | 7.723365 | 0.415310 | 1.680555 | 3629.000000 | 5.875788 | 0.254560 | 1.228830 |
| max | 129.235000 | 1.848930 | 165.729000 | 214.970000 | 1.093390 | 1.068000 | 176.237000 | 5044.920000 | 17733.950000 | 38282.710000 | ... | 98.045380 | 20.241920 | 6.575930 | 15.340060 | 0.773210 | 4.258000 | 4953.000000 | 31.145250 | 0.533340 | 3.867300 |
8 rows × 62 columns
dfs = {}
for column in Futures_orig.columns:
# Create a new DataFrame for each column using the same index
dfs[column] = pd.DataFrame(Futures_orig[column])
beginning_dates_dict = {}
for header in beginning_headers:
if header in dfs:
print(f"{header}:")
beginning_date = dfs[header].apply(lambda col: col.first_valid_index()).iloc[0]
beginning_dates_dict[header] = beginning_date
print(f'Beginning date for: {beginning_date}')
print(dfs[header].isnull().sum())
num_rows_before = len(dfs[header].index)
print(f'Number of rows for {header} before dropping NAs: {num_rows_before}')
dfs[header].dropna(inplace=True)
print(dfs[header].isnull().sum())
num_rows_after = len(dfs[header].index)
print(f'Number of rows for {header} after dropping NAs: {num_rows_after}')
print("-" * 40) # Just for visual separation between outputs
else:
print(f"The key '{header}' does not exist in the dfs dictionary.")
# Convert the beginning dates dictionary to a DataFrame
beginning_dates_df = pd.DataFrame(list(beginning_dates_dict.items()), columns=['Header', 'Beginning Date'])
# Convert string dates to datetime objects if they are not already (skip if not necessary)
for header, date_str in beginning_dates_dict.items():
beginning_dates_dict[header] = pd.to_datetime(date_str)
# Filter the dictionary to include only dates greater than 1999
beginning_dates_after_1999_list = [header for header, date in beginning_dates_dict.items() if date.year > 1999]
USD Future: Beginning date for: 1999-01-04 00:00:00 USD Future 75 dtype: int64 Number of rows for USD Future before dropping NAs: 6521 USD Future 0 dtype: int64 Number of rows for USD Future after dropping NAs: 6446 ---------------------------------------- EUR Future (USD): Beginning date for: 1999-01-04 00:00:00 EUR Future (USD) 179 dtype: int64 Number of rows for EUR Future (USD) before dropping NAs: 6521 EUR Future (USD) 0 dtype: int64 Number of rows for EUR Future (USD) after dropping NAs: 6342 ---------------------------------------- JPY Future (USD): Beginning date for: 1999-01-04 00:00:00 JPY Future (USD) 178 dtype: int64 Number of rows for JPY Future (USD) before dropping NAs: 6521 JPY Future (USD) 0 dtype: int64 Number of rows for JPY Future (USD) after dropping NAs: 6343 ---------------------------------------- GBP Future (USD): Beginning date for: 1999-01-04 00:00:00 GBP Future (USD) 178 dtype: int64 Number of rows for GBP Future (USD) before dropping NAs: 6521 GBP Future (USD) 0 dtype: int64 Number of rows for GBP Future (USD) after dropping NAs: 6343 ---------------------------------------- GBP Future (EUR): Beginning date for: 1999-01-12 00:00:00 GBP Future (EUR) 471 dtype: int64 Number of rows for GBP Future (EUR) before dropping NAs: 6521 GBP Future (EUR) 0 dtype: int64 Number of rows for GBP Future (EUR) after dropping NAs: 6050 ---------------------------------------- CAD Future (USD): Beginning date for: 1999-01-04 00:00:00 CAD Future (USD) 179 dtype: int64 Number of rows for CAD Future (USD) before dropping NAs: 6521 CAD Future (USD) 0 dtype: int64 Number of rows for CAD Future (USD) after dropping NAs: 6342 ---------------------------------------- CHF Future (USD): Beginning date for: 1999-01-04 00:00:00 CHF Future (USD) 176 dtype: int64 Number of rows for CHF Future (USD) before dropping NAs: 6521 CHF Future (USD) 0 dtype: int64 Number of rows for CHF Future (USD) after dropping NAs: 6345 ---------------------------------------- S&P 500: Beginning date for: 1999-01-04 00:00:00 S&P 500 181 dtype: int64 Number of rows for S&P 500 before dropping NAs: 6521 S&P 500 0 dtype: int64 Number of rows for S&P 500 after dropping NAs: 6340 ---------------------------------------- Nasdaq 100: Beginning date for: 1999-06-22 00:00:00 Nasdaq 100 295 dtype: int64 Number of rows for Nasdaq 100 before dropping NAs: 6521 Nasdaq 100 0 dtype: int64 Number of rows for Nasdaq 100 after dropping NAs: 6226 ---------------------------------------- DJIA: Beginning date for: 2002-04-05 00:00:00 DJIA 1037 dtype: int64 Number of rows for DJIA before dropping NAs: 6521 DJIA 0 dtype: int64 Number of rows for DJIA after dropping NAs: 5484 ---------------------------------------- Russell 2000: Beginning date for: 2017-07-11 00:00:00 Russell 2000 4888 dtype: int64 Number of rows for Russell 2000 before dropping NAs: 6521 Russell 2000 0 dtype: int64 Number of rows for Russell 2000 after dropping NAs: 1633 ---------------------------------------- S&P 400: Beginning date for: 2002-01-29 00:00:00 S&P 400 974 dtype: int64 Number of rows for S&P 400 before dropping NAs: 6521 S&P 400 0 dtype: int64 Number of rows for S&P 400 after dropping NAs: 5547 ---------------------------------------- S&P Canada 60: Beginning date for: 1999-09-08 00:00:00 S&P Canada 60 414 dtype: int64 Number of rows for S&P Canada 60 before dropping NAs: 6521 S&P Canada 60 0 dtype: int64 Number of rows for S&P Canada 60 after dropping NAs: 6107 ---------------------------------------- FTSE 100: Beginning date for: 1999-01-04 00:00:00 FTSE 100 115 dtype: int64 Number of rows for FTSE 100 before dropping NAs: 6521 FTSE 100 0 dtype: int64 Number of rows for FTSE 100 after dropping NAs: 6406 ---------------------------------------- DAX: Beginning date for: 1999-01-04 00:00:00 DAX 153 dtype: int64 Number of rows for DAX before dropping NAs: 6521 DAX 0 dtype: int64 Number of rows for DAX after dropping NAs: 6368 ---------------------------------------- SMI: Beginning date for: 1999-01-04 00:00:00 SMI 167 dtype: int64 Number of rows for SMI before dropping NAs: 6521 SMI 0 dtype: int64 Number of rows for SMI after dropping NAs: 6354 ---------------------------------------- CAC - 40: Beginning date for: 1999-01-05 00:00:00 CAC - 40 106 dtype: int64 Number of rows for CAC - 40 before dropping NAs: 6521 CAC - 40 0 dtype: int64 Number of rows for CAC - 40 after dropping NAs: 6415 ---------------------------------------- IBEX 35: Beginning date for: 1999-01-04 00:00:00 IBEX 35 162 dtype: int64 Number of rows for IBEX 35 before dropping NAs: 6521 IBEX 35 0 dtype: int64 Number of rows for IBEX 35 after dropping NAs: 6359 ---------------------------------------- MIB 30: Beginning date for: 2004-03-23 00:00:00 MIB 30 1494 dtype: int64 Number of rows for MIB 30 before dropping NAs: 6521 MIB 30 0 dtype: int64 Number of rows for MIB 30 after dropping NAs: 5027 ---------------------------------------- OMX: Beginning date for: 2005-02-15 00:00:00 OMX 1772 dtype: int64 Number of rows for OMX before dropping NAs: 6521 OMX 0 dtype: int64 Number of rows for OMX after dropping NAs: 4749 ---------------------------------------- Euro Stoxx 50: Beginning date for: 1999-01-04 00:00:00 Euro Stoxx 50 153 dtype: int64 Number of rows for Euro Stoxx 50 before dropping NAs: 6521 Euro Stoxx 50 0 dtype: int64 Number of rows for Euro Stoxx 50 after dropping NAs: 6368 ---------------------------------------- SPI 200: Beginning date for: 2000-05-03 00:00:00 SPI 200 447 dtype: int64 Number of rows for SPI 200 before dropping NAs: 6521 SPI 200 0 dtype: int64 Number of rows for SPI 200 after dropping NAs: 6074 ---------------------------------------- Nikkei 225: Beginning date for: 1999-01-04 00:00:00 Nikkei 225 392 dtype: int64 Number of rows for Nikkei 225 before dropping NAs: 6521 Nikkei 225 0 dtype: int64 Number of rows for Nikkei 225 after dropping NAs: 6129 ---------------------------------------- Hang Seng Index: Beginning date for: 1999-01-04 00:00:00 Hang Seng Index 330 dtype: int64 Number of rows for Hang Seng Index before dropping NAs: 6521 Hang Seng Index 0 dtype: int64 Number of rows for Hang Seng Index after dropping NAs: 6191 ---------------------------------------- US MSCI EAFE: Beginning date for: 2009-09-09 00:00:00 US MSCI EAFE 2831 dtype: int64 Number of rows for US MSCI EAFE before dropping NAs: 6521 US MSCI EAFE 0 dtype: int64 Number of rows for US MSCI EAFE after dropping NAs: 3690 ---------------------------------------- US 2-year: Beginning date for: 1999-01-04 00:00:00 US 2-year 224 dtype: int64 Number of rows for US 2-year before dropping NAs: 6521 US 2-year 0 dtype: int64 Number of rows for US 2-year after dropping NAs: 6297 ---------------------------------------- US 5-year: Beginning date for: 1999-01-04 00:00:00 US 5-year 227 dtype: int64 Number of rows for US 5-year before dropping NAs: 6521 US 5-year 0 dtype: int64 Number of rows for US 5-year after dropping NAs: 6294 ---------------------------------------- US 10-year: Beginning date for: 1999-01-04 00:00:00 US 10-year 232 dtype: int64 Number of rows for US 10-year before dropping NAs: 6521 US 10-year 0 dtype: int64 Number of rows for US 10-year after dropping NAs: 6289 ---------------------------------------- US Ultra 10-year: Beginning date for: 2016-01-12 00:00:00 US Ultra 10-year 4512 dtype: int64 Number of rows for US Ultra 10-year before dropping NAs: 6521 US Ultra 10-year 0 dtype: int64 Number of rows for US Ultra 10-year after dropping NAs: 2009 ---------------------------------------- US 30-year: Beginning date for: 2010-01-12 00:00:00 US 30-year 2997 dtype: int64 Number of rows for US 30-year before dropping NAs: 6521 US 30-year 0 dtype: int64 Number of rows for US 30-year after dropping NAs: 3524 ---------------------------------------- Short Gilt (2 year): Beginning date for: 2009-11-24 00:00:00 Short Gilt (2 year) 2888 dtype: int64 Number of rows for Short Gilt (2 year) before dropping NAs: 6521 Short Gilt (2 year) 0 dtype: int64 Number of rows for Short Gilt (2 year) after dropping NAs: 3633 ---------------------------------------- Medium Gilt (5 year): Beginning date for: 2009-11-24 00:00:00 Medium Gilt (5 year) 2888 dtype: int64 Number of rows for Medium Gilt (5 year) before dropping NAs: 6521 Medium Gilt (5 year) 0 dtype: int64 Number of rows for Medium Gilt (5 year) after dropping NAs: 3633 ---------------------------------------- Long Gilt (10 year): Beginning date for: 1999-01-04 00:00:00 Long Gilt (10 year) 111 dtype: int64 Number of rows for Long Gilt (10 year) before dropping NAs: 6521 Long Gilt (10 year) 0 dtype: int64 Number of rows for Long Gilt (10 year) after dropping NAs: 6410 ---------------------------------------- Euro-Schatz-Futures (2 year): Beginning date for: 1999-01-04 00:00:00 Euro-Schatz-Futures (2 year) 149 dtype: int64 Number of rows for Euro-Schatz-Futures (2 year) before dropping NAs: 6521 Euro-Schatz-Futures (2 year) 0 dtype: int64 Number of rows for Euro-Schatz-Futures (2 year) after dropping NAs: 6372 ---------------------------------------- Euro-Bobl-Future (5 year): Beginning date for: 1999-01-04 00:00:00 Euro-Bobl-Future (5 year) 151 dtype: int64 Number of rows for Euro-Bobl-Future (5 year) before dropping NAs: 6521 Euro-Bobl-Future (5 year) 0 dtype: int64 Number of rows for Euro-Bobl-Future (5 year) after dropping NAs: 6370 ---------------------------------------- Euro-Bund-Future (10 year): Beginning date for: 1999-01-04 00:00:00 Euro-Bund-Future (10 year) 150 dtype: int64 Number of rows for Euro-Bund-Future (10 year) before dropping NAs: 6521 Euro-Bund-Future (10 year) 0 dtype: int64 Number of rows for Euro-Bund-Future (10 year) after dropping NAs: 6371 ---------------------------------------- Euro-Buxl-Future (30 year): Beginning date for: 1999-01-04 00:00:00 Euro-Buxl-Future (30 year) 176 dtype: int64 Number of rows for Euro-Buxl-Future (30 year) before dropping NAs: 6521 Euro-Buxl-Future (30 year) 0 dtype: int64 Number of rows for Euro-Buxl-Future (30 year) after dropping NAs: 6345 ---------------------------------------- Brent Crude Oil: Beginning date for: 1999-01-04 00:00:00 Brent Crude Oil 107 dtype: int64 Number of rows for Brent Crude Oil before dropping NAs: 6521 Brent Crude Oil 0 dtype: int64 Number of rows for Brent Crude Oil after dropping NAs: 6414 ---------------------------------------- WTI Crude Oil: Beginning date for: 1999-01-04 00:00:00 WTI Crude Oil 279 dtype: int64 Number of rows for WTI Crude Oil before dropping NAs: 6521 WTI Crude Oil 0 dtype: int64 Number of rows for WTI Crude Oil after dropping NAs: 6242 ---------------------------------------- Heating Oil: Beginning date for: 1999-01-04 00:00:00 Heating Oil 280 dtype: int64 Number of rows for Heating Oil before dropping NAs: 6521 Heating Oil 0 dtype: int64 Number of rows for Heating Oil after dropping NAs: 6241 ---------------------------------------- RBOB Gasoline: Beginning date for: 2005-10-04 00:00:00 RBOB Gasoline 1958 dtype: int64 Number of rows for RBOB Gasoline before dropping NAs: 6521 RBOB Gasoline 0 dtype: int64 Number of rows for RBOB Gasoline after dropping NAs: 4563 ---------------------------------------- Natural Gas: Beginning date for: 1999-01-04 00:00:00 Natural Gas 241 dtype: int64 Number of rows for Natural Gas before dropping NAs: 6521 Natural Gas 0 dtype: int64 Number of rows for Natural Gas after dropping NAs: 6280 ---------------------------------------- Gold: Beginning date for: 1999-01-04 00:00:00 Gold 239 dtype: int64 Number of rows for Gold before dropping NAs: 6521 Gold 0 dtype: int64 Number of rows for Gold after dropping NAs: 6282 ---------------------------------------- Silver: Beginning date for: 1999-01-04 00:00:00 Silver 240 dtype: int64 Number of rows for Silver before dropping NAs: 6521 Silver 0 dtype: int64 Number of rows for Silver after dropping NAs: 6281 ---------------------------------------- Platinum: Beginning date for: 1999-01-04 00:00:00 Platinum 241 dtype: int64 Number of rows for Platinum before dropping NAs: 6521 Platinum 0 dtype: int64 Number of rows for Platinum after dropping NAs: 6280 ---------------------------------------- Palladium: Beginning date for: 1999-01-04 00:00:00 Palladium 242 dtype: int64 Number of rows for Palladium before dropping NAs: 6521 Palladium 0 dtype: int64 Number of rows for Palladium after dropping NAs: 6279 ---------------------------------------- Copper: Beginning date for: 1999-01-04 00:00:00 Copper 240 dtype: int64 Number of rows for Copper before dropping NAs: 6521 Copper 0 dtype: int64 Number of rows for Copper after dropping NAs: 6281 ---------------------------------------- Nickel: Beginning date for: 1999-01-04 00:00:00 Nickel 231 dtype: int64 Number of rows for Nickel before dropping NAs: 6521 Nickel 0 dtype: int64 Number of rows for Nickel after dropping NAs: 6290 ---------------------------------------- Zinc: Beginning date for: 1999-01-04 00:00:00 Zinc 213 dtype: int64 Number of rows for Zinc before dropping NAs: 6521 Zinc 0 dtype: int64 Number of rows for Zinc after dropping NAs: 6308 ---------------------------------------- Lean hogs: Beginning date for: 1999-01-04 00:00:00 Lean hogs 220 dtype: int64 Number of rows for Lean hogs before dropping NAs: 6521 Lean hogs 0 dtype: int64 Number of rows for Lean hogs after dropping NAs: 6301 ---------------------------------------- Live cattle: Beginning date for: 1999-01-04 00:00:00 Live cattle 221 dtype: int64 Number of rows for Live cattle before dropping NAs: 6521 Live cattle 0 dtype: int64 Number of rows for Live cattle after dropping NAs: 6300 ---------------------------------------- Feeder cattle: Beginning date for: 1999-01-04 00:00:00 Feeder cattle 223 dtype: int64 Number of rows for Feeder cattle before dropping NAs: 6521 Feeder cattle 0 dtype: int64 Number of rows for Feeder cattle after dropping NAs: 6298 ---------------------------------------- Wheat: Beginning date for: 1999-01-04 00:00:00 Wheat 223 dtype: int64 Number of rows for Wheat before dropping NAs: 6521 Wheat 0 dtype: int64 Number of rows for Wheat after dropping NAs: 6298 ---------------------------------------- Corn: Beginning date for: 1999-01-04 00:00:00 Corn 224 dtype: int64 Number of rows for Corn before dropping NAs: 6521 Corn 0 dtype: int64 Number of rows for Corn after dropping NAs: 6297 ---------------------------------------- Oat: Beginning date for: 1999-01-04 00:00:00 Oat 223 dtype: int64 Number of rows for Oat before dropping NAs: 6521 Oat 0 dtype: int64 Number of rows for Oat after dropping NAs: 6298 ---------------------------------------- Soybeans: Beginning date for: 1999-01-04 00:00:00 Soybeans 225 dtype: int64 Number of rows for Soybeans before dropping NAs: 6521 Soybeans 0 dtype: int64 Number of rows for Soybeans after dropping NAs: 6296 ---------------------------------------- Soybean oil: Beginning date for: 1999-01-04 00:00:00 Soybean oil 222 dtype: int64 Number of rows for Soybean oil before dropping NAs: 6521 Soybean oil 0 dtype: int64 Number of rows for Soybean oil after dropping NAs: 6299 ---------------------------------------- Frozen orange juice: Beginning date for: 1999-01-04 00:00:00 Frozen orange juice 206 dtype: int64 Number of rows for Frozen orange juice before dropping NAs: 6521 Frozen orange juice 0 dtype: int64 Number of rows for Frozen orange juice after dropping NAs: 6315 ---------------------------------------- Cocoa: Beginning date for: 1999-01-04 00:00:00 Cocoa 250 dtype: int64 Number of rows for Cocoa before dropping NAs: 6521 Cocoa 0 dtype: int64 Number of rows for Cocoa after dropping NAs: 6271 ---------------------------------------- Coffee: Beginning date for: 1999-01-04 00:00:00 Coffee 251 dtype: int64 Number of rows for Coffee before dropping NAs: 6521 Coffee 0 dtype: int64 Number of rows for Coffee after dropping NAs: 6270 ---------------------------------------- Sugar No.11: Beginning date for: 1999-01-04 00:00:00 Sugar No.11 251 dtype: int64 Number of rows for Sugar No.11 before dropping NAs: 6521 Sugar No.11 0 dtype: int64 Number of rows for Sugar No.11 after dropping NAs: 6270 ---------------------------------------- Cotton No.2: Beginning date for: 1999-01-04 00:00:00 Cotton No.2 212 dtype: int64 Number of rows for Cotton No.2 before dropping NAs: 6521 Cotton No.2 0 dtype: int64 Number of rows for Cotton No.2 after dropping NAs: 6309 ----------------------------------------
beginning_dates_after_1999_list
['DJIA', 'Russell 2000', 'S&P 400', 'MIB 30', 'OMX', 'SPI 200', 'US MSCI EAFE', 'US Ultra 10-year', 'US 30-year', 'Short Gilt (2 year)', 'Medium Gilt (5 year)', 'RBOB Gasoline']
new_headers = [header for header in beginning_headers if header not in beginning_dates_after_1999_list]
Futures = Futures_orig.drop(columns=beginning_dates_after_1999_list)
for header in beginning_dates_after_1999_list:
if header in dfs:
del dfs[header]
corr_matrix = Futures.corr()
plt.figure(figsize=(50, 50))
sns.heatmap(corr_matrix, annot=True, fmt=".2f")
plt.show()
# Define the slices for each DataFrame as a dictionary
slices = {
'FX': (0, 7),
'Equity': (7, 18),
'Rates': (18, 26),
'Commodity': (26, 50),
'Energy': (26, 30),
'Metals': (30, 37),
'Agriculture': (37, 50),
}
for name, (start_col, end_col) in slices.items():
temp_df = Futures.iloc[:, start_col:end_col]
corr_matrix = temp_df.corr()
#Plot
plt.figure(figsize=(10, 8))
sns.heatmap(corr_matrix, annot=True, fmt=".2f")
plt.title(f'{name} Correlation Matrix')
plt.show()
## Used to create the Statistics --> WTI not changed
# Initialize a DataFrame to store the annualized metrics
annualized_metrics_df_statistics = pd.DataFrame(columns=['Header', 'Annualized Mean Return', 'Annualized Volatility'])
for header in new_headers:
if header in dfs:
# Calculate daily returns
dfs[header]['Daily Returns'] = dfs[header][header].pct_change()
dfs[header]['Log Returns'] = np.log(dfs[header][header] / dfs[header][header].shift(1))
# Calculate annualized mean return and volatility
daily_mean_return = dfs[header]['Daily Returns'].mean()
annualized_mean_return_statistics = daily_mean_return * 252
daily_volatility = dfs[header]['Daily Returns'].std()
annualized_volatility_statistics = daily_volatility * np.sqrt(252)
# Append the metrics to the annualized_metrics_df DataFrame
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
'Annualized Mean Return': annualized_mean_return_statistics,
'Annualized Volatility': annualized_volatility_statistics},
ignore_index=True)
else:
print(f"The key '{header}' does not exist in the dfs dictionary.")
annualized_metrics_df_statistics.set_index('Header', inplace = True)
annualized_metrics_to_use = annualized_metrics_df_statistics.T
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
C:\Users\Raphael\anaconda3\lib\site-packages\pandas\core\arraylike.py:402: RuntimeWarning: invalid value encountered in log
result = getattr(ufunc, method)(*inputs, **kwargs)
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
<ipython-input-10-1115b33ec1c3>:19: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
annualized_metrics_df_statistics = annualized_metrics_df_statistics.append({'Header': header,
## Used for Calculation of the Strategies --> Zero Value of WTI set to "zero"
for header in new_headers:
if header in dfs:
dfs[header][header] = np.where(dfs[header][header] <= 0, 0.01, dfs[header][header])
# Calculate daily returns using adjusted prices
dfs[header]['Daily Returns'] = dfs[header][header].pct_change()
dfs[header]['Log Returns'] = np.log(dfs[header][header] / dfs[header][header].shift(1))
else:
print(f"The key '{header}' does not exist in the dfs dictionary.")
Summary_statistics = Futures.describe()
beginning_dates_orig = beginning_dates_df.set_index('Header')
beginning_dates_transposed = beginning_dates_orig.T
beginning_dates_clean = beginning_dates_transposed.drop(columns=beginning_dates_after_1999_list)
Summary_statistics_appended = pd.concat([Summary_statistics, beginning_dates_clean, annualized_metrics_to_use])
Summary_statistics_appended_dropped = Summary_statistics_appended.drop(['mean', 'std', '25%', '50%', '75%'])
Summary_statistics_for_Thesis = Summary_statistics_appended_dropped.T
Summary_statistics_for_Thesis.to_excel('Summary_statistics.xlsx')
<ipython-input-12-3cc21df50464>:11: UserWarning: Pandas requires version '1.4.3' or newer of 'xlsxwriter' (version '1.3.8' currently installed).
Summary_statistics_for_Thesis.to_excel('Summary_statistics.xlsx')
import plotly.graph_objects as go
features = new_headers
for feature in features:
trace = go.Scatter(x=Futures.index, y=Futures[feature], mode='lines', name='Closing Price')
data = [trace]
layout = go.Layout(title=f'{feature} over Time', xaxis=dict(title='Days'), yaxis=dict(title=f'{feature} Price'))
fig = go.Figure(data=data, layout=layout)
fig.show()
# Line Zinc
trace_Zinc = go.Scatter(
x=Futures.index,
y=Futures['Zinc'],
mode='lines',
name='Zinc'
)
# Combine all traces
data = [trace_Zinc]
# Define layout
layout = go.Layout(
title={
'text': 'Zinc price over time',
'y': 0.9,
'x': 0.5,
'xanchor': 'center',
'yanchor': 'top',
'font': dict(size=18, color='black', family='Arial'),
},
plot_bgcolor='white',
paper_bgcolor='white',
xaxis=dict(
showgrid=True,
gridcolor='lightgrey',
tickangle=-45 # Rotate the x-axis labels by 45 degrees
),
yaxis=dict(
title='Zinc price',
showgrid=True,
gridcolor='lightgrey'
)
)
# Create figure and add data and layout
fig = go.Figure(data=data, layout=layout)
# Show the figure
fig.show()
# Window sizes for the moving averages
short_SMA = 1
long_SMA = 200
# Iterate over the headers and apply the moving averages
for header in new_headers:
if header in dfs:
# Calculate the short-window moving average and add it as a new column
dfs[header][f'SMA_{short_SMA}'] = dfs[header][header].rolling(window=short_SMA).mean()
# Calculate the long-window moving average and add it as a new column
dfs[header][f'SMA_{long_SMA}'] = dfs[header][header].rolling(window=long_SMA).mean()
else:
print(f"DataFrame for {header} not found in dfs.")
# Iterate over the headers and apply the moving averages
for header in new_headers:
if header in dfs:
# Generate signals
dfs[header]['Signal_SMA'] = 0
# Buy signal when
dfs[header]['Signal_SMA'] = np.where(dfs[header][f'SMA_{short_SMA}'] > dfs[header][f'SMA_{long_SMA}'], 1, dfs[header]['Signal_SMA'])
# Sell signal
dfs[header]['Signal_SMA'] = np.where(dfs[header][f'SMA_{short_SMA}'] < dfs[header][f'SMA_{long_SMA}'], -1, dfs[header]['Signal_SMA'])
# Generate trading orders
# Conditions
Buy = dfs[header]['Signal_SMA'].diff() > 0
Sell = dfs[header]['Signal_SMA'].diff() < 0
# Choices based on conditions
choices = [1, -1]
# Use np.select to apply conditions and choices
dfs[header]['Trades_SMA'] = np.select([Buy, Sell], choices, default=0)
else:
print(f"DataFrame for {header} not found in dfs.")
# Window sizes
short_SMA_with_Band = 1
long_SMA_with_Band = 200
Band_width = 0.01
# Iterate over the headers and apply the moving averages
for header in new_headers:
if header in dfs:
# Calculate the short-window moving average and add it as a new column
dfs[header][f'SMA_{short_SMA_with_Band}_with_Band'] = dfs[header][header].rolling(window=short_SMA).mean()
# Calculate the long-window moving average and add it as a new column
dfs[header][f'SMA_{long_SMA_with_Band}_with_Band'] = dfs[header][header].rolling(window=long_SMA).mean()
# Calculate 1% price band
dfs[header]['SMA_with_Band_UpperBand'] = dfs[header][f'SMA_{long_SMA_with_Band}_with_Band'] * (1 + Band_width)
dfs[header]['SMA_with_Band_LowerBand'] = dfs[header][f'SMA_{long_SMA_with_Band}_with_Band'] * (1 - Band_width)
else:
print(f"DataFrame for {header} not found in dfs.")
for header in new_headers:
if header in dfs:
dfs[header]['Signal_SMA_with_Band'] = 0
# Generate initial buy and sell signals based on SMA and Band conditions
dfs[header]['Signal_SMA_with_Band'] = np.where(
(dfs[header][f'SMA_{short_SMA_with_Band}_with_Band'] > dfs[header][f'SMA_{long_SMA_with_Band}_with_Band']) &
(dfs[header][f'SMA_{short_SMA_with_Band}_with_Band'] > dfs[header]['SMA_with_Band_UpperBand']), 1,
dfs[header]['Signal_SMA_with_Band']
)
dfs[header]['Signal_SMA_with_Band'] = np.where(
(dfs[header][f'SMA_{short_SMA_with_Band}_with_Band'] < dfs[header][f'SMA_{long_SMA_with_Band}_with_Band']) &
(dfs[header][f'SMA_{short_SMA_with_Band}_with_Band'] < dfs[header]['SMA_with_Band_LowerBand']), -1,
dfs[header]['Signal_SMA_with_Band']
)
# To ensure that we only consider "real changes" in the signal,
# we need to track the last non-zero signal.
# We can do this by creating a temporary Series that holds the last non-zero value seen at each step.
last_non_zero_signal_with_Band = dfs[header]['Signal_SMA_with_Band'].replace(0, np.nan).ffill().fillna(0)
# Now, generate 'Position_SMA_with_Band' based on real changes
real_change_buy_with_Band = (dfs[header]['Signal_SMA_with_Band'] == 1) & (last_non_zero_signal_with_Band.shift(1) == -1)
real_change_sell_with_Band = (dfs[header]['Signal_SMA_with_Band'] == -1) & (last_non_zero_signal_with_Band.shift(1) == 1)
# Use np.select to apply the real change conditions
dfs[header]['Trades_SMA_with_Band'] = np.select([real_change_buy_with_Band, real_change_sell_with_Band], [1, -1], default=0)
else:
print(f"DataFrame for {header} not found in dfs.")
# Window size
TSMOM_window = 252 # 12-month momentum
TSMOM_window_month = int(TSMOM_window / 21)
# Iterate over the headers and apply the moving averages
for header in new_headers:
if header in dfs:
# Calculate the short-window moving average and add it as a new column
dfs[header][f'TSMOM_{TSMOM_window_month}'] = dfs[header]['Log Returns'].rolling(window=TSMOM_window).sum().shift(1)
else:
print(f"DataFrame for {header} not found in dfs.")
# Iterate over the headers and apply the moving averages
for header in new_headers:
# Make sure the DataFrame exists in your dictionary
if header in dfs:
# Generate signals
dfs[header][f'Signal_TSMOM_{TSMOM_window_month}'] = 0
# Buy signal when
dfs[header][f'Signal_TSMOM_{TSMOM_window_month}'] = np.where(dfs[header][f'TSMOM_{TSMOM_window_month}'] > 0, 1, dfs[header][f'Signal_TSMOM_{TSMOM_window_month}'])
# Sell signal
dfs[header][f'Signal_TSMOM_{TSMOM_window_month}'] = np.where(dfs[header][f'TSMOM_{TSMOM_window_month}'] < 0, -1, dfs[header][f'Signal_TSMOM_{TSMOM_window_month}'])
# Generate trading orders
# Conditions
Buy = dfs[header][f'Signal_TSMOM_{TSMOM_window_month}'].diff() > 0
Sell = dfs[header][f'Signal_TSMOM_{TSMOM_window_month}'].diff() < 0
# Choices based on conditions
choices = [1, -1]
# Use np.select to apply conditions and choices
dfs[header][f'Trades_TSMOM_{TSMOM_window_month}'] = np.select([Buy, Sell], choices, default=0)
else:
print(f"DataFrame for {header} not found in dfs.")
# Window size
RAMOM_window = 25 # 25-day momentum
RAMOM_window_month = RAMOM_window
RAMOM_return_window = 12 # according to Dudler et al they used 12-day returns
RAMOM_volatlity_window = 5 # according to Dudler et al they used 5 day realized volatility
# Iterate over the headers and apply the moving averages
for header in new_headers:
if header in dfs:
# Calculate the short-window moving average and add it as a new column
RAMOM_Signal_Return = dfs[header]['Log Returns'].rolling(window=RAMOM_return_window).sum()
RAMOM_Signal_Volatility = dfs[header]['Log Returns'].rolling(window=RAMOM_volatlity_window).std()
dfs[header]['Risk_adjusted_momentum'] = RAMOM_Signal_Return / RAMOM_Signal_Volatility
dfs[header][f'RAMOM_{RAMOM_window_month}'] = dfs[header]['Risk_adjusted_momentum'].rolling(window=RAMOM_window).sum()
else:
print(f"DataFrame for {header} not found in dfs.")
# Iterate over the headers and apply the moving averages
for header in new_headers:
if header in dfs:
# Generate signals
dfs[header][f'Signal_RAMOM_{RAMOM_window_month}'] = 0
# Buy signal when
dfs[header][f'Signal_RAMOM_{RAMOM_window_month}'] = np.where(dfs[header][f'RAMOM_{RAMOM_window_month}'] > 0, 1, dfs[header][f'Signal_RAMOM_{RAMOM_window_month}'])
# Sell signal
dfs[header][f'Signal_RAMOM_{RAMOM_window_month}'] = np.where(dfs[header][f'RAMOM_{RAMOM_window_month}'] < 0, -1, dfs[header][f'Signal_RAMOM_{RAMOM_window_month}'])
# Generate trading orders
# Conditions
Buy = dfs[header][f'Signal_RAMOM_{RAMOM_window_month}'].diff() > 0
Sell = dfs[header][f'Signal_RAMOM_{RAMOM_window_month}'].diff() < 0
# Choices based on conditions
choices = [1, -1]
# Use np.select to apply conditions and choices
dfs[header][f'Trades_RAMOM_{RAMOM_window_month}'] = np.select([Buy, Sell], choices, default=0)
else:
print(f"DataFrame for {header} not found in dfs.")
# Iterate over the headers and apply the moving averages
for header in new_headers:
if header in dfs:
# Initialize the Kalman filter
kf = KalmanFilter(initial_state_mean=0,
initial_state_covariance=1,
observation_covariance=1,
transition_covariance=1,
transition_matrices=[1],
observation_matrices=[1])
# Use the observed 'Last Price' as the measurement
state_means, state_covariances = kf.filter(dfs[header][header])
# The `state_means` variable contains the filtered state estimates
dfs[header]['Kalman_Filter_Price'] = state_means
else:
print(f"DataFrame for {header} not found in dfs.")
# Iterate over the headers and apply the moving averages
for header in new_headers:
if header in dfs:
# Generate signals
dfs[header]['Signal_Kalman_Filter'] = 0
# Buy signal (Oversold)
dfs[header]['Signal_Kalman_Filter'] = np.where(dfs[header][header] < dfs[header]['Kalman_Filter_Price'], 1, dfs[header]['Signal_Kalman_Filter'])
# Sell signal (Overbought)
dfs[header]['Signal_Kalman_Filter'] = np.where(dfs[header][header] > dfs[header]['Kalman_Filter_Price'], -1, dfs[header]['Signal_Kalman_Filter'])
# Generate trading orders
# Conditions
Buy = dfs[header]['Signal_Kalman_Filter'].diff() > 0
Sell = dfs[header]['Signal_Kalman_Filter'].diff() < 0
# Choices based on conditions
choices = [1, -1]
# Use np.select to apply conditions and choices
dfs[header]['Trades_Kalman_Filter'] = np.select([Buy, Sell], choices, default=0)
else:
print(f"DataFrame for {header} not found in dfs.")
# when do we want to start our strategy, so we can slize the dataframe
strategy_start = '2000-01-01'
# SMA
strategy_SMA = {} # This will store the strategy DataFrames
for header in new_headers: # Ensure new_headers is a list of columns in Futures_orig you're interested in
# Initialize the strategy SMA DataFrame
df_strategy_SMA = pd.DataFrame(index=dfs[header].index)
df_strategy_SMA[f'{header}_Price'] = dfs[header][header]
df_strategy_SMA['Log_Return'] = dfs[header]['Log Returns']
df_strategy_SMA['Simple_Return'] = dfs[header]['Daily Returns']
df_strategy_SMA[f'SMA_{short_SMA}'] = dfs[header][f'SMA_{short_SMA}']
df_strategy_SMA[f'SMA_{long_SMA}'] = dfs[header][f'SMA_{long_SMA}']
df_strategy_SMA['Signal_SMA_shifted'] = dfs[header]['Signal_SMA'].shift(1)
df_strategy_SMA['Trades_SMA'] = dfs[header]['Trades_SMA'].shift(1)
df_strategy_SMA['Cumulative_Log_Returns'] = float(0)
# Convert the index to datetime format
df_strategy_SMA.index = pd.to_datetime(df_strategy_SMA.index)
# Store this strategy DataFrame in the dictionary
strategy_SMA[header] = df_strategy_SMA
# SMA_bands
strategy_SMA_bands = {} # This will store the strategy DataFrames
for header in new_headers: # Ensure new_headers is a list of columns in Futures_orig you're interested in
# Initialize the strategy SMA DataFrame
df_strategy_SMA_bands = pd.DataFrame(index=dfs[header].index)
df_strategy_SMA_bands[f'{header}_Price'] = dfs[header][header]
df_strategy_SMA_bands['Log_Return'] = dfs[header]['Log Returns']
df_strategy_SMA_bands['Simple_Return'] = dfs[header]['Daily Returns']
df_strategy_SMA_bands[f'SMA_{short_SMA_with_Band}_with_Band'] = dfs[header][f'SMA_{short_SMA_with_Band}_with_Band']
df_strategy_SMA_bands[f'SMA_{long_SMA_with_Band}_with_Band'] = dfs[header][f'SMA_{long_SMA_with_Band}_with_Band']
df_strategy_SMA_bands['SMA_with_Band_UpperBand'] = dfs[header]['SMA_with_Band_UpperBand']
df_strategy_SMA_bands['SMA_with_Band_LowerBand'] = dfs[header]['SMA_with_Band_LowerBand']
df_strategy_SMA_bands['Signal_SMA_with_Band_shifted'] = dfs[header]['Signal_SMA_with_Band'].shift(1)
df_strategy_SMA_bands['Trades_SMA_with_Band'] = dfs[header]['Trades_SMA_with_Band'].shift(1)
df_strategy_SMA_bands['Cumulative_Log_Returns'] = float(0)
# Convert the index to datetime format
df_strategy_SMA_bands.index = pd.to_datetime(df_strategy_SMA_bands.index)
# Store this strategy DataFrame in the dictionary
strategy_SMA_bands[header] = df_strategy_SMA_bands
# TSMOM
strategy_TSMOM = {} # This will store the strategy DataFrames
for header in new_headers: # Ensure new_headers is a list of columns in Futures_orig you're interested in
# Initialize the strategy SMA DataFrame
df_strategy_TSMOM = pd.DataFrame(index=dfs[header].index)
df_strategy_TSMOM[f'{header}_Price'] = dfs[header][header]
df_strategy_TSMOM['Log_Return'] = dfs[header]['Log Returns']
df_strategy_TSMOM['Simple_Return'] = dfs[header]['Daily Returns']
df_strategy_TSMOM[f'TSMOM_{TSMOM_window_month}'] = dfs[header][f'TSMOM_{TSMOM_window_month}']
df_strategy_TSMOM[f'Signal_TSMOM_{TSMOM_window_month}_shifted'] = dfs[header][f'Signal_TSMOM_{TSMOM_window_month}'].shift(1)
df_strategy_TSMOM[f'Trades_TSMOM_{TSMOM_window_month}'] = dfs[header][f'Trades_TSMOM_{TSMOM_window_month}'].shift(1)
df_strategy_TSMOM['Cumulative_Log_Returns'] = float(0)
# Convert the index to datetime format
df_strategy_TSMOM.index = pd.to_datetime(df_strategy_TSMOM.index)
# Store this strategy DataFrame in the dictionary
strategy_TSMOM[header] = df_strategy_TSMOM
# RAMOM
strategy_RAMOM = {} # This will store the strategy DataFrames
for header in new_headers: # Ensure new_headers is a list of columns in Futures_orig you're interested in
# Initialize the strategy SMA DataFrame
df_strategy_RAMOM = pd.DataFrame(index=dfs[header].index)
df_strategy_RAMOM[f'{header}_Price'] = dfs[header][header]
df_strategy_RAMOM['Log_Return'] = dfs[header]['Log Returns']
df_strategy_RAMOM['Simple_Return'] = dfs[header]['Daily Returns']
df_strategy_RAMOM['Risk_adjusted_momentum'] = dfs[header]['Risk_adjusted_momentum']
df_strategy_RAMOM[f'RAMOM_{RAMOM_window_month}'] = dfs[header][f'RAMOM_{RAMOM_window_month}']
df_strategy_RAMOM[f'Signal_RAMOM_{RAMOM_window_month}_shifted'] = dfs[header][f'Signal_RAMOM_{RAMOM_window_month}'].shift(1)
df_strategy_RAMOM[f'Trades_RAMOM_{RAMOM_window_month}'] = dfs[header][f'Trades_RAMOM_{RAMOM_window_month}'].shift(1)
df_strategy_RAMOM['Cumulative_Log_Returns'] = float(0)
# Convert the index to datetime format
df_strategy_RAMOM.index = pd.to_datetime(df_strategy_RAMOM.index)
# Store this strategy DataFrame in the dictionary
strategy_RAMOM[header] = df_strategy_RAMOM
# Kalman
strategy_kalman = {} # This will store the strategy DataFrames
for header in new_headers: # Ensure new_headers is a list of columns in Futures_orig you're interested in
# Initialize the strategy SMA DataFrame
df_strategy_kalman = pd.DataFrame(index=dfs[header].index)
df_strategy_kalman[f'{header}_Price'] = dfs[header][header]
df_strategy_kalman['Log_Return'] = dfs[header]['Log Returns']
df_strategy_kalman['Simple_Return'] = dfs[header]['Daily Returns']
df_strategy_kalman['Kalman_Filter_Price'] = dfs[header]['Kalman_Filter_Price']
df_strategy_kalman['Signal_Kalman_Filter_shifted'] = dfs[header]['Signal_Kalman_Filter'].shift(1)
df_strategy_kalman['Trades_Kalman_Filter'] = dfs[header]['Trades_Kalman_Filter'].shift(1)
df_strategy_kalman['Cumulative_Log_Returns'] = float(0)
# Convert the index to datetime format
df_strategy_kalman.index = pd.to_datetime(df_strategy_kalman.index)
# Store this strategy DataFrame in the dictionary
strategy_kalman[header] = df_strategy_kalman
strategy_start = '2000-01-01'
start_date = strategy_start
initial_investment = 1000000
#initial_investment = 1000000
#strategy_start = '2000-01-01'
for header in new_headers:
# Running total of log returns based on trade signals
running_total = float(0)
# Find the next available date in the DataFrame index closest to strategy_start
start_date_index = strategy_SMA[header].index.get_loc(pd.to_datetime(strategy_start), method='backfill')
start_date = strategy_SMA[header].index[start_date_index]
for date, row in strategy_SMA[header].iterrows():
# Skip the rows before the adjusted strategy start date
if date < start_date:
continue
# Update Trades only on the adjusted strategy start date
if date == start_date:
strategy_SMA[header].loc[date, 'Trades_SMA'] = row['Signal_SMA_shifted']
# Update running total based on trade signals
if row['Signal_SMA_shifted'] == 1: # Buy signal
running_total += row['Log_Return']
elif row['Signal_SMA_shifted'] == -1: # Sell signal
running_total -= row['Log_Return']
# Calculate cumulative returns
cumulative_log_return = np.exp(running_total) - 1
# Store the running total and the cumulative returns in the DataFrame
strategy_SMA[header].loc[date, 'Cumulative_Log_Returns'] = running_total
strategy_SMA[header].loc[date, 'Total_Log_Return'] = initial_investment * (1 + cumulative_log_return)
<ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-27-ac3db5de6a92>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead.
what_to_plot = 'Zinc'
#start_date = '2000-01-01'
# Filter the DataFrame to include only data from the start_date onwards
filtered_data = strategy_SMA[what_to_plot][strategy_SMA[what_to_plot].index >= pd.to_datetime(start_date)]
# Creating the trace for the current feature from the filtered data
trace = go.Scatter(x=filtered_data.index, y=filtered_data['Cumulative_Log_Returns'], mode='lines', name='Cumulative Log Returns')
# Creating the data list with the current trace
data = [trace]
# Creating the layout for the current plot, dynamically setting the title to the current feature
layout = go.Layout(title=f"{what_to_plot} - SMA Strategy over Time", xaxis=dict(title='Days'), yaxis=dict(title='Value'))
# Creating the figure with the current data and layout
fig = go.Figure(data=data, layout=layout)
# Displaying the figure
fig.show()
#what_to_plot = 'WTI Crude Oil'
#start_date = '2000-01-01'
# Filter the DataFrame to include only data from the start_date onwards
filtered_data = strategy_SMA[what_to_plot][strategy_SMA[what_to_plot].index >= pd.to_datetime(start_date)]
# Calculate the number of trades from the filtered data
no_trades = filtered_data['Trades_SMA'].abs().sum()
print(f"Number of Trades: {int(no_trades)}")
# Calculate the minimum total log return from the filtered data
min_strategy = filtered_data['Total_Log_Return'].min()
day_min = filtered_data['Total_Log_Return'].idxmin()
print(f"Min per strategy: {min_strategy:,.2f}")
print(f"Day with min: {day_min.strftime('%Y-%m-%d')}")
# Calculate the maximum total log return from the filtered data
max_strategy = filtered_data['Total_Log_Return'].max()
day_max = filtered_data['Total_Log_Return'].idxmax()
print(f"Max per strategy: {max_strategy:,.2f}")
print(f"Day with max: {day_max.strftime('%Y-%m-%d')}")
Number of Trades: 163 Min per strategy: 885,229.94 Day with min: 2000-10-11 Max per strategy: 13,953,827.37 Day with max: 2022-04-19
# Filter the DataFrame to only include data from the start_date onwards
filtered_data = strategy_SMA[what_to_plot][strategy_SMA[what_to_plot].index >= pd.to_datetime(start_date)]
# Create a figure with secondary y-axis
fig = make_subplots(specs=[[{"secondary_y": True}]])
# Add the closing price trace from the filtered data
fig.add_trace(
go.Scatter(x=filtered_data.index, y=filtered_data[f'{what_to_plot}_Price'], mode='lines', name='Closing price'),
secondary_y=False,
)
# Add the short moving average trace from the filtered data
fig.add_trace(
go.Scatter(x=filtered_data.index, y=filtered_data[f'SMA_{short_SMA}'], mode='lines', name=f'{short_SMA}-day MA'),
secondary_y=False,
)
# Add the long moving average trace from the filtered data
fig.add_trace(
go.Scatter(x=filtered_data.index, y=filtered_data[f'SMA_{long_SMA}'], mode='lines', name=f'{long_SMA}-day MA'),
secondary_y=False,
)
# Filter for buy signals and create a trace
fig.add_trace(
go.Scatter(
x=filtered_data[filtered_data['Trades_SMA'] == 1].index,
y=filtered_data[filtered_data['Trades_SMA'] == 1][f'{what_to_plot}_Price'],
mode='markers',
name='Buy signal',
marker=dict(
color='green',
size=10,
symbol='triangle-up'
)
),
secondary_y=False,
)
# Filter for sell signals and create a trace
fig.add_trace(
go.Scatter(
x=filtered_data[filtered_data['Trades_SMA'] == -1].index,
y=filtered_data[filtered_data['Trades_SMA'] == -1][f'{what_to_plot}_Price'],
mode='markers',
name='Sell signal',
marker=dict(
color='red',
size=10,
symbol='triangle-down'
)
),
secondary_y=False,
)
# Add the Total Portfolio trace from the filtered data
fig.add_trace(
go.Scatter(x=filtered_data.index, y=filtered_data['Total_Log_Return'], mode='lines', name='Portfolio value', line=dict(color='rgb(44, 160, 44)')),
secondary_y=True,
)
# Add figure title with custom font settings
fig.update_layout(
title={
'text': f'{what_to_plot} - SMA strategy',
'y':0.9,
'x':0.5,
'xanchor': 'center',
'yanchor': 'top',
'font': dict(size=18, color='black', family='Arial')
},
plot_bgcolor='white',
paper_bgcolor='white',
xaxis=dict(
showgrid=True,
gridcolor='lightgrey',
tickangle=-45 # Rotate the x-axis labels by 45 degrees
),
yaxis=dict(
showgrid=True,
gridcolor='lightgrey'
),
yaxis2=dict(
showgrid=True,
gridcolor='lightgrey'
)
)
# Set y-axes titles
fig.update_yaxes(title_text=f'{what_to_plot} price', secondary_y=False)
fig.update_yaxes(title_text='Portfolio value', secondary_y=True)
# Show the figure
fig.show()
#initial_investment = 1000000
#strategy_start = '2000-01-01'
for header in new_headers:
# Running total of log returns based on trade signals
running_total = float(0)
# Find the next available date in the DataFrame index closest to strategy_start
start_date_index = strategy_SMA_bands[header].index.get_loc(pd.to_datetime(strategy_start), method='backfill')
start_date = strategy_SMA_bands[header].index[start_date_index]
for date, row in strategy_SMA_bands[header].iterrows():
# Skip the rows before the adjusted strategy start date
if date < start_date:
continue
# Update Trades only on the adjusted strategy start date
if date == start_date:
strategy_SMA_bands[header].loc[date, 'Trades_SMA_with_Band'] = row['Signal_SMA_with_Band_shifted']
# Update running total based on trade signals
if row['Signal_SMA_with_Band_shifted'] == 1: # Buy signal
running_total += row['Log_Return']
elif row['Signal_SMA_with_Band_shifted'] == -1: # Sell signal
running_total -= row['Log_Return']
# Calculate cumulative returns
cumulative_log_return = np.exp(running_total) - 1
# Store the running total in the Cumulative_Returns column of the same DataFrame
strategy_SMA_bands[header].loc[date, 'Cumulative_Log_Returns'] = running_total
strategy_SMA_bands[header].loc[date, 'Total_Log_Return'] = initial_investment * (1 + cumulative_log_return)
<ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-31-68602d2f75c2>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead.
what_to_plot = 'Zinc'
# start_date = '2000-01-01'
# Filter the DataFrame to include only data from the start_date onwards
filtered_data = strategy_SMA_bands[what_to_plot][strategy_SMA_bands[what_to_plot].index >= pd.to_datetime(start_date)]
# Creating the trace for the current feature from the filtered data
trace = go.Scatter(
x=filtered_data.index,
y=filtered_data['Total_Log_Return'],
mode='lines',
name='Total Log Return'
)
# Creating the data list with the current trace
data = [trace]
# Creating the layout for the current plot, dynamically setting the title to the current feature
layout = go.Layout(
title=f"{what_to_plot} - SMA with Bands Strategy over Time",
xaxis=dict(title='Days'),
yaxis=dict(title='Value')
)
# Creating the figure with the current data and layout
fig = go.Figure(data=data, layout=layout)
# Displaying the figure
fig.show()
#what_to_plot = 'WTI Crude Oil'
#start_date = '2000-01-01'
# Filter the DataFrame to include only data from the start_date onwards
filtered_data = strategy_SMA_bands[what_to_plot][strategy_SMA_bands[what_to_plot].index >= pd.to_datetime(start_date)]
# Calculate the number of trades from the filtered data
no_trades = filtered_data['Trades_SMA_with_Band'].abs().sum()
print(f"Number of Trades: {int(no_trades)}")
# Calculate the minimum total log return from the filtered data
min_strategy = filtered_data['Total_Log_Return'].min()
day_min = filtered_data['Total_Log_Return'].idxmin()
print(f"Min per strategy: {min_strategy:,.2f}")
print(f"Day with min: {day_min.strftime('%Y-%m-%d')}")
# Calculate the maximum total log return from the filtered data
max_strategy = filtered_data['Total_Log_Return'].max()
day_max = filtered_data['Total_Log_Return'].idxmax()
print(f"Max per strategy: {max_strategy:,.2f}")
print(f"Day with max: {day_max.strftime('%Y-%m-%d')}")
Number of Trades: 91 Min per strategy: 843,142.84 Day with min: 2000-10-11 Max per strategy: 11,062,789.32 Day with max: 2022-04-19
# Filter the DataFrame to only include data from the start_date onwards
filtered_data = strategy_SMA_bands[what_to_plot][strategy_SMA_bands[what_to_plot].index >= pd.to_datetime(start_date)]
# Create a figure with secondary y-axis
fig = make_subplots(specs=[[{"secondary_y": True}]])
# Add the closing price trace from the filtered data
fig.add_trace(
go.Scatter(x=filtered_data.index, y=filtered_data[f'{what_to_plot}_Price'], mode='lines', name='Closing price'),
secondary_y=False,
)
# Add the upper band trace from the filtered data
fig.add_trace(
go.Scatter(x=filtered_data.index, y=filtered_data['SMA_with_Band_UpperBand'], mode='lines', name='Upper band'),
secondary_y=False,
)
# Add the lower band trace from the filtered data
fig.add_trace(
go.Scatter(x=filtered_data.index, y=filtered_data['SMA_with_Band_LowerBand'], mode='lines', name='Lower band'),
secondary_y=False,
)
# Filter for buy signals and create a trace
fig.add_trace(
go.Scatter(
x=filtered_data[filtered_data['Trades_SMA_with_Band'] == 1].index,
y=filtered_data[filtered_data['Trades_SMA_with_Band'] == 1][f'{what_to_plot}_Price'],
mode='markers',
name='Buy signal',
marker=dict(
color='green',
size=10,
symbol='triangle-up'
)
),
secondary_y=False,
)
# Filter for sell signals and create a trace
fig.add_trace(
go.Scatter(
x=filtered_data[filtered_data['Trades_SMA_with_Band'] == -1].index,
y=filtered_data[filtered_data['Trades_SMA_with_Band'] == -1][f'{what_to_plot}_Price'],
mode='markers',
name='Sell signal',
marker=dict(
color='red',
size=10,
symbol='triangle-down'
)
),
secondary_y=False,
)
# Add the Total Portfolio trace from the filtered data
fig.add_trace(
go.Scatter(x=filtered_data.index, y=filtered_data['Total_Log_Return'], mode='lines', name='Portfolio value', line=dict(color='rgb(44, 160, 44)')),
secondary_y=True,
)
# Add figure title with custom font settings
fig.update_layout(
title={
'text': f'{what_to_plot} - SMA with bands strategy',
'y':0.9,
'x':0.5,
'xanchor': 'center',
'yanchor': 'top',
'font': dict(size=18, color='black', family='Arial')
},
plot_bgcolor='white',
paper_bgcolor='white',
xaxis=dict(
showgrid=True,
gridcolor='lightgrey',
tickangle=-45 # Rotate the x-axis labels by 45 degrees
),
yaxis=dict(
showgrid=True,
gridcolor='lightgrey'
),
yaxis2=dict(
showgrid=True,
gridcolor='lightgrey'
)
)
# Set y-axes titles
fig.update_yaxes(title_text=f'{what_to_plot} price', secondary_y=False)
fig.update_yaxes(title_text='Portfolio value', secondary_y=True)
# Show the figure
fig.show()
#initial_investment = 1000000
#strategy_start = '2000-01-01'
for header in new_headers:
# Running total of log returns based on trade signals
running_total = float(0)
# Find the next available date in the DataFrame index closest to strategy_start
start_date_index = strategy_TSMOM[header].index.get_loc(pd.to_datetime(strategy_start), method='backfill')
start_date = strategy_TSMOM[header].index[start_date_index]
for date, row in strategy_TSMOM[header].iterrows():
# Skip the rows before the adjusted strategy start date
if date < start_date:
continue
# Update Trades only on the adjusted strategy start date
if date == start_date:
strategy_TSMOM[header].loc[date, f'Trades_TSMOM_{TSMOM_window_month}'] = row[f'Signal_TSMOM_{TSMOM_window_month}_shifted']
# Update running total based on trade signals
if row[f'Signal_TSMOM_{TSMOM_window_month}_shifted'] == 1: # Buy signal
running_total += row['Log_Return']
elif row[f'Signal_TSMOM_{TSMOM_window_month}_shifted'] == -1: # Sell signal
running_total -= row['Log_Return']
# Calculate cumulative returns
cumulative_log_return = np.exp(running_total) - 1
# Store the running total in the Cumulative_Returns column of the same DataFrame
strategy_TSMOM[header].loc[date, 'Cumulative_Log_Returns'] = running_total
strategy_TSMOM[header].loc[date, 'Total_Log_Return'] = initial_investment * (1 + cumulative_log_return)
<ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-35-c6477c451acb>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead.
#what_to_plot = 'Zinc'
#start_date = '2000-01-01'
# Filter the DataFrame to include only data from the start_date onwards
filtered_data = strategy_TSMOM[what_to_plot][strategy_TSMOM[what_to_plot].index >= pd.to_datetime(start_date)]
# Creating the trace for the current feature from the filtered data
trace = go.Scatter(
x=filtered_data.index,
y=filtered_data['Total_Log_Return'],
mode='lines',
name='Total Log Return'
)
# Creating the data list with the current trace
data = [trace]
# Creating the layout for the current plot, dynamically setting the title to the current feature
layout = go.Layout(
title=f"{what_to_plot} - TSMOM Strategy over Time",
xaxis=dict(title='Days'),
yaxis=dict(title='Value')
)
# Creating the figure with the current data and layout
fig = go.Figure(data=data, layout=layout)
# Displaying the figure
fig.show()
#what_to_plot = 'WTI Crude Oil'
#start_date = '2000-01-01'
# Filter the DataFrame to include only data from the start_date onwards
filtered_data = strategy_TSMOM[what_to_plot][strategy_TSMOM[what_to_plot].index >= pd.to_datetime(start_date)]
# Calculate the number of trades from the filtered data
no_trades = filtered_data[f'Trades_TSMOM_{TSMOM_window_month}'].abs().sum()
print(f"Number of Trades: {int(no_trades)}")
# Calculate the minimum total log return from the filtered data
min_strategy = filtered_data['Total_Log_Return'].min()
day_min = filtered_data['Total_Log_Return'].idxmin()
print(f"Min per strategy: {min_strategy:,.2f}")
print(f"Day with min: {day_min.strftime('%Y-%m-%d')}")
# Calculate the maximum total log return from the filtered data
max_strategy = filtered_data['Total_Log_Return'].max()
day_max = filtered_data['Total_Log_Return'].idxmax()
print(f"Max per strategy: {max_strategy:,.2f}")
print(f"Day with max: {day_max.strftime('%Y-%m-%d')}")
Number of Trades: 150 Min per strategy: 618,720.08 Day with min: 2000-09-12 Max per strategy: 11,291,071.96 Day with max: 2008-12-12
# Filter the DataFrame to only include data from the start_date onwards
filtered_data = strategy_TSMOM[what_to_plot][strategy_TSMOM[what_to_plot].index >= pd.to_datetime(start_date)]
# Create a figure with secondary y-axis
fig = make_subplots(specs=[[{"secondary_y": True}]])
# Add the closing price trace from the filtered data
fig.add_trace(
go.Scatter(x=filtered_data.index, y=filtered_data[f'{what_to_plot}_Price'], mode='lines', name='Closing price'),
secondary_y=False,
)
# Filter for buy signals and create a trace
fig.add_trace(
go.Scatter(
x=filtered_data[filtered_data[f'Trades_TSMOM_{TSMOM_window_month}'] == 1].index,
y=filtered_data[filtered_data[f'Trades_TSMOM_{TSMOM_window_month}'] == 1][f'{what_to_plot}_Price'],
mode='markers',
name='Buy signal',
marker=dict(
color='green',
size=10,
symbol='triangle-up'
)
),
secondary_y=False,
)
# Filter for sell signals and create a trace
fig.add_trace(
go.Scatter(
x=filtered_data[filtered_data[f'Trades_TSMOM_{TSMOM_window_month}'] == -1].index,
y=filtered_data[filtered_data[f'Trades_TSMOM_{TSMOM_window_month}'] == -1][f'{what_to_plot}_Price'],
mode='markers',
name='Sell signal',
marker=dict(
color='red',
size=10,
symbol='triangle-down'
)
),
secondary_y=False,
)
# Add the Total Portfolio trace from the filtered data
fig.add_trace(
go.Scatter(x=filtered_data.index, y=filtered_data['Total_Log_Return'], mode='lines', name='Portfolio value', line=dict(color='rgb(44, 160, 44)')),
secondary_y=True,
)
# Add figure title with custom font settings
fig.update_layout(
title={
'text': f'{what_to_plot} - TSMOM strategy',
'y':0.9,
'x':0.5,
'xanchor': 'center',
'yanchor': 'top',
'font': dict(size=18, color='black', family='Arial')
},
plot_bgcolor='white',
paper_bgcolor='white',
xaxis=dict(
showgrid=True,
gridcolor='lightgrey',
tickangle=-45 # Rotate the x-axis labels by 45 degrees
),
yaxis=dict(
showgrid=True,
gridcolor='lightgrey'
),
yaxis2=dict(
showgrid=True,
gridcolor='lightgrey'
)
)
# Set y-axes titles
fig.update_yaxes(title_text=f'{what_to_plot} price', secondary_y=False)
fig.update_yaxes(title_text='Portfolio value', secondary_y=True)
# Show the figure
fig.show()
#initial_investment = 1000000
#strategy_start = '2000-01-01'
for header in new_headers:
# Running total of log returns based on trade signals
running_total = float(0)
# Find the next available date in the DataFrame index closest to strategy_start
start_date_index = strategy_RAMOM[header].index.get_loc(pd.to_datetime(strategy_start), method='backfill')
start_date = strategy_RAMOM[header].index[start_date_index]
for date, row in strategy_RAMOM[header].iterrows():
# Skip the rows before the adjusted strategy start date
if date < start_date:
continue
# Update Trades only on the adjusted strategy start date
if date == start_date:
strategy_RAMOM[header].loc[date, f'Trades_RAMOM_{RAMOM_window_month}'] = row[f'Signal_RAMOM_{RAMOM_window_month}_shifted']
# Update running total based on trade signals
if row[f'Signal_RAMOM_{RAMOM_window_month}_shifted'] == 1: # Buy signal
running_total += row['Log_Return']
elif row[f'Signal_RAMOM_{RAMOM_window_month}_shifted'] == -1: # Sell signal
running_total -= row['Log_Return']
# Calculate cumulative returns
cumulative_log_return = np.exp(running_total) - 1
# Store the running total in the Cumulative_Returns column of the same DataFrame
strategy_RAMOM[header].loc[date, 'Cumulative_Log_Returns'] = running_total
strategy_RAMOM[header].loc[date, 'Total_Log_Return'] = initial_investment * (1 + cumulative_log_return)
<ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-39-e89eba58ffa3>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead.
#what_to_plot = 'Zinc'
#start_date = '2000-01-01'
# Filter the DataFrame to only include data from the start_date onwards
filtered_data = strategy_RAMOM[what_to_plot][strategy_RAMOM[what_to_plot].index >= pd.to_datetime(start_date)]
# Creating the trace for the current feature from the filtered data
trace = go.Scatter(
x=filtered_data.index,
y=filtered_data['Total_Log_Return'],
mode='lines',
name='Total Log Return'
)
# Creating the data list with the current trace
data = [trace]
# Creating the layout for the current plot, dynamically setting the title to the current feature
layout = go.Layout(
title=f"{what_to_plot} - RAMOM Strategy over Time",
xaxis=dict(title='Days'),
yaxis=dict(title='Value')
)
# Creating the figure with the current data and layout
fig = go.Figure(data=data, layout=layout)
# Displaying the figure
fig.show()
#what_to_plot = 'WTI Crude Oil'
#start_date = '2000-01-01'
# Filter the DataFrame to include only data from the start_date onwards
filtered_data = strategy_RAMOM[what_to_plot][strategy_RAMOM[what_to_plot].index >= pd.to_datetime(start_date)]
# Calculate the number of trades from the filtered data
no_trades = filtered_data[f'Trades_RAMOM_{RAMOM_window_month}'].abs().sum()
print(f"Number of Trades: {int(no_trades)}")
# Calculate the minimum total log return from the filtered data
min_strategy = filtered_data['Total_Log_Return'].min()
day_min = filtered_data['Total_Log_Return'].idxmin()
print(f"Min per strategy: {min_strategy:,.2f}")
print(f"Day with min: {day_min.strftime('%Y-%m-%d')}")
# Calculate the maximum total log return from the filtered data
max_strategy = filtered_data['Total_Log_Return'].max()
day_max = filtered_data['Total_Log_Return'].idxmax()
print(f"Max per strategy: {max_strategy:,.2f}")
print(f"Day with max: {day_max.strftime('%Y-%m-%d')}")
Number of Trades: 156 Min per strategy: 828,911.37 Day with min: 2000-08-09 Max per strategy: 5,758,511.77 Day with max: 2008-11-07
# Filter the DataFrame to only include data from the start_date onwards
filtered_data = strategy_RAMOM[what_to_plot][strategy_RAMOM[what_to_plot].index >= pd.to_datetime(start_date)]
# Create a figure with secondary y-axis
fig = make_subplots(specs=[[{"secondary_y": True}]])
# Add the closing price trace from the filtered data
fig.add_trace(
go.Scatter(x=filtered_data.index, y=filtered_data[f'{what_to_plot}_Price'], mode='lines', name='Closing price'),
secondary_y=False,
)
# Filter for buy signals and create a trace
fig.add_trace(
go.Scatter(
x=filtered_data[filtered_data[f'Trades_RAMOM_{RAMOM_window_month}'] == 1].index,
y=filtered_data[filtered_data[f'Trades_RAMOM_{RAMOM_window_month}'] == 1][f'{what_to_plot}_Price'],
mode='markers',
name='Buy signal',
marker=dict(
color='green',
size=10,
symbol='triangle-up'
)
),
secondary_y=False,
)
# Filter for sell signals and create a trace
fig.add_trace(
go.Scatter(
x=filtered_data[filtered_data[f'Trades_RAMOM_{RAMOM_window_month}'] == -1].index,
y=filtered_data[filtered_data[f'Trades_RAMOM_{RAMOM_window_month}'] == -1][f'{what_to_plot}_Price'],
mode='markers',
name='Sell signal',
marker=dict(
color='red',
size=10,
symbol='triangle-down'
)
),
secondary_y=False,
)
# Add the Total Portfolio trace from the filtered data
fig.add_trace(
go.Scatter(x=filtered_data.index, y=filtered_data['Total_Log_Return'], mode='lines', name='Portfolio value', line=dict(color='rgb(44, 160, 44)')),
secondary_y=True,
)
# Add figure title with custom font settings
fig.update_layout(
title={
'text': f'{what_to_plot} - RAMOM strategy',
'y':0.9,
'x':0.5,
'xanchor': 'center',
'yanchor': 'top',
'font': dict(size=18, color='black', family='Arial')
},
plot_bgcolor='white',
paper_bgcolor='white',
xaxis=dict(
showgrid=True,
gridcolor='lightgrey',
tickangle=-45 # Rotate the x-axis labels by 45 degrees
),
yaxis=dict(
showgrid=True,
gridcolor='lightgrey'
),
yaxis2=dict(
showgrid=True,
gridcolor='lightgrey'
)
)
# Set y-axes titles
fig.update_yaxes(title_text=f'{what_to_plot} price', secondary_y=False)
fig.update_yaxes(title_text='Portfolio value', secondary_y=True)
# Show the figure
fig.show()
#initial_investment = 1000000
#strategy_start = '2000-01-01'
for header in new_headers:
# Running total of log returns based on trade signals
running_total = float(0)
# Find the next available date in the DataFrame index closest to strategy_start
start_date_index = strategy_kalman[header].index.get_loc(pd.to_datetime(strategy_start), method='backfill')
start_date = strategy_kalman[header].index[start_date_index]
for date, row in strategy_kalman[header].iterrows():
# Skip the rows before the adjusted strategy start date
if date < start_date:
continue
# Update Trades only on the adjusted strategy start date
if date == start_date:
strategy_kalman[header].loc[date, 'Trades_Kalman_Filter'] = row['Signal_Kalman_Filter_shifted']
# Update running total based on trade signals
if row['Signal_Kalman_Filter_shifted'] == 1: # Buy signal
running_total += row['Log_Return']
elif row['Signal_Kalman_Filter_shifted'] == -1: # Sell signal
running_total -= row['Log_Return']
# Calculate cumulative returns
cumulative_log_return = np.exp(running_total) - 1
# Store the running total in the Cumulative_Returns column of the same DataFrame
strategy_kalman[header].loc[date, 'Cumulative_Log_Returns'] = running_total
strategy_kalman[header].loc[date, 'Total_Log_Return'] = initial_investment * (1 + cumulative_log_return)
<ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead. <ipython-input-43-8e74fa085888>:9: FutureWarning: Passing method to DatetimeIndex.get_loc is deprecated and will raise in a future version. Use index.get_indexer([item], method=...) instead.
what_to_plot = 'Zinc'
start_date = '2000-01-01'
# Filter the DataFrame to only include data from the start_date onwards
filtered_data = strategy_kalman[what_to_plot][strategy_kalman[what_to_plot].index >= pd.to_datetime(start_date)]
# Creating the trace for the current feature from the filtered data
trace = go.Scatter(
x=filtered_data.index,
y=filtered_data['Total_Log_Return'],
mode='lines',
name='Total Log Return'
)
# Creating the data list with the current trace
data = [trace]
# Creating the layout for the current plot, dynamically setting the title to the current feature
layout = go.Layout(
title=f"{what_to_plot} - Kalman Filter Strategy over Time",
xaxis=dict(title='Days'),
yaxis=dict(title='Value')
)
# Creating the figure with the current data and layout
fig = go.Figure(data=data, layout=layout)
# Displaying the figure
fig.show()
#what_to_plot = 'WTI Crude Oil'
#start_date = '2000-01-01'
# Filter the DataFrame to include only data from the start_date onwards
filtered_data = strategy_kalman[what_to_plot][strategy_kalman[what_to_plot].index >= pd.to_datetime(start_date)]
# Calculate the number of trades from the filtered data
no_trades = filtered_data['Trades_Kalman_Filter'].abs().sum()
print(f"Number of Trades: {int(no_trades)}")
# Calculate the minimum total log return from the filtered data
min_strategy = filtered_data['Total_Log_Return'].min()
day_min = filtered_data['Total_Log_Return'].idxmin()
print(f"Min per strategy: {min_strategy:,.2f}")
print(f"Day with min: {day_min.strftime('%Y-%m-%d')}")
# Calculate the maximum total log return from the filtered data
max_strategy = filtered_data['Total_Log_Return'].max()
day_max = filtered_data['Total_Log_Return'].idxmax()
print(f"Max per strategy: {max_strategy:,.2f}")
print(f"Day with max: {day_max.strftime('%Y-%m-%d')}")
Number of Trades: 2263 Min per strategy: 652,909.92 Day with min: 2008-01-03 Max per strategy: 1,794,610.97 Day with max: 2005-05-03
# Filter the DataFrame to only include data from the start_date onwards
filtered_data = strategy_kalman[what_to_plot][strategy_kalman[what_to_plot].index >= pd.to_datetime(start_date)]
# Create a figure with secondary y-axis
fig = make_subplots(specs=[[{"secondary_y": True}]])
# Add the closing price trace from the filtered data
fig.add_trace(
go.Scatter(x=filtered_data.index, y=filtered_data[f'{what_to_plot}_Price'], mode='lines', name='Closing price'),
secondary_y=False,
)
# Add the kalman filter price trace from the filtered data
fig.add_trace(
go.Scatter(x=filtered_data.index, y=filtered_data['Kalman_Filter_Price'], mode='lines', name='Kalman filter price'),
secondary_y=False,
)
# Filter for buy signals and create a trace
fig.add_trace(
go.Scatter(
x=filtered_data[filtered_data['Trades_Kalman_Filter'] == 1].index,
y=filtered_data[filtered_data['Trades_Kalman_Filter'] == 1][f'{what_to_plot}_Price'],
mode='markers',
name='Buy signal',
marker=dict(
color='green',
size=10,
symbol='triangle-up'
)
),
secondary_y=False,
)
# Filter for sell signals and create a trace
fig.add_trace(
go.Scatter(
x=filtered_data[filtered_data['Trades_Kalman_Filter'] == -1].index,
y=filtered_data[filtered_data['Trades_Kalman_Filter'] == -1][f'{what_to_plot}_Price'],
mode='markers',
name='Sell signal',
marker=dict(
color='red',
size=10,
symbol='triangle-down'
)
),
secondary_y=False,
)
# Add the Total Portfolio trace from the filtered data
fig.add_trace(
go.Scatter(x=filtered_data.index, y=filtered_data['Total_Log_Return'], mode='lines', name='Portfolio value', line=dict(color='rgb(44, 160, 44)')),
secondary_y=True,
)
# Add figure title with custom font settings
fig.update_layout(
title={
'text': f'{what_to_plot} - Kalman filter strategy',
'y':0.9,
'x':0.5,
'xanchor': 'center',
'yanchor': 'top',
'font': dict(size=18, color='black', family='Arial')
},
plot_bgcolor='white',
paper_bgcolor='white',
xaxis=dict(
showgrid=True,
gridcolor='lightgrey',
tickangle=-45 # Rotate the x-axis labels by 45 degrees
),
yaxis=dict(
showgrid=True,
gridcolor='lightgrey'
),
yaxis2=dict(
showgrid=True,
gridcolor='lightgrey'
)
)
# Set y-axes titles
fig.update_yaxes(title_text=f'{what_to_plot} price', secondary_y=False)
fig.update_yaxes(title_text='Portfolio value', secondary_y=True)
# Show the figure
fig.show()
for header, df in strategy_SMA.items():
print(f"strategy_SMA['{header}']")
print('-' * 40)
print('Nr. of Futures: ' + str(len(strategy_SMA)))
strategy_SMA['USD Future'] strategy_SMA['EUR Future (USD)'] strategy_SMA['JPY Future (USD)'] strategy_SMA['GBP Future (USD)'] strategy_SMA['GBP Future (EUR)'] strategy_SMA['CAD Future (USD)'] strategy_SMA['CHF Future (USD)'] strategy_SMA['S&P 500'] strategy_SMA['Nasdaq 100'] strategy_SMA['S&P Canada 60'] strategy_SMA['FTSE 100'] strategy_SMA['DAX'] strategy_SMA['SMI'] strategy_SMA['CAC - 40'] strategy_SMA['IBEX 35'] strategy_SMA['Euro Stoxx 50'] strategy_SMA['Nikkei 225'] strategy_SMA['Hang Seng Index'] strategy_SMA['US 2-year'] strategy_SMA['US 5-year'] strategy_SMA['US 10-year'] strategy_SMA['Long Gilt (10 year)'] strategy_SMA['Euro-Schatz-Futures (2 year)'] strategy_SMA['Euro-Bobl-Future (5 year)'] strategy_SMA['Euro-Bund-Future (10 year)'] strategy_SMA['Euro-Buxl-Future (30 year)'] strategy_SMA['Brent Crude Oil'] strategy_SMA['WTI Crude Oil'] strategy_SMA['Heating Oil'] strategy_SMA['Natural Gas'] strategy_SMA['Gold'] strategy_SMA['Silver'] strategy_SMA['Platinum'] strategy_SMA['Palladium'] strategy_SMA['Copper'] strategy_SMA['Nickel'] strategy_SMA['Zinc'] strategy_SMA['Lean hogs'] strategy_SMA['Live cattle'] strategy_SMA['Feeder cattle'] strategy_SMA['Wheat'] strategy_SMA['Corn'] strategy_SMA['Oat'] strategy_SMA['Soybeans'] strategy_SMA['Soybean oil'] strategy_SMA['Frozen orange juice'] strategy_SMA['Cocoa'] strategy_SMA['Coffee'] strategy_SMA['Sugar No.11'] strategy_SMA['Cotton No.2'] ---------------------------------------- Nr. of Futures: 50
#start_date = '2000-01-01'
# List to hold the data series
data_series_list_SMA = []
# Extract 'Cumulative_Log_Returns' and rename it uniquely
for name, df in strategy_SMA.items():
if 'Cumulative_Log_Returns' in df.columns:
# Filter the DataFrame to include only data from the start_date onwards
filtered_df = df[df.index >= pd.to_datetime(start_date)]
# Rename the series with its asset name and add to the list
series = filtered_df['Cumulative_Log_Returns'].rename(name)
data_series_list_SMA.append(series)
# Combine all the series into a single DataFrame
combined_df_SMA = pd.concat(data_series_list_SMA, axis=1, join='outer')
# Forward fill missing values
combined_df_SMA_filled = combined_df_SMA.ffill()
# Drop rows where any NaN values still exist (likely at the start)
combined_df_SMA_cleaned = combined_df_SMA_filled.dropna()
pd.set_option('display.max_columns', None)
combined_df_SMA_cleaned.head()
| USD Future | EUR Future (USD) | JPY Future (USD) | GBP Future (USD) | GBP Future (EUR) | CAD Future (USD) | CHF Future (USD) | S&P 500 | Nasdaq 100 | S&P Canada 60 | FTSE 100 | DAX | SMI | CAC - 40 | IBEX 35 | Euro Stoxx 50 | Nikkei 225 | Hang Seng Index | US 2-year | US 5-year | US 10-year | Long Gilt (10 year) | Euro-Schatz-Futures (2 year) | Euro-Bobl-Future (5 year) | Euro-Bund-Future (10 year) | Euro-Buxl-Future (30 year) | Brent Crude Oil | WTI Crude Oil | Heating Oil | Natural Gas | Gold | Silver | Platinum | Palladium | Copper | Nickel | Zinc | Lean hogs | Live cattle | Feeder cattle | Wheat | Corn | Oat | Soybeans | Soybean oil | Frozen orange juice | Cocoa | Coffee | Sugar No.11 | Cotton No.2 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Date | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 2000-01-04 | -0.017301 | -0.018726 | -0.010262 | 0.011188 | 0.000000 | -0.002950 | -0.019341 | -0.050080 | 0.0 | 0.0 | -0.024268 | -0.031807 | -0.015051 | -0.026219 | -0.025887 | -0.033067 | 0.002820 | 0.000763 | 0.000966 | 0.000927 | 0.002986 | -0.001479 | 0.002047 | 0.003393 | -0.016893 | 0.013577 | -0.027977 | -0.001862 | -0.001331 | 0.067950 | -0.020597 | -0.014430 | -0.020354 | -0.016386 | -0.017536 | -0.015752 | -0.018352 | 0.020434 | -0.007572 | 0.004970 | 5.042964e-03 | 0.007362 | 2.290204e-03 | -0.003716 | 0.012554 | -0.024958 | 0.000955 | -0.079745 | -0.058878 | 0.000196 |
| 2000-01-05 | -0.017797 | -0.020362 | -0.021354 | 0.014146 | 0.000000 | -0.001474 | -0.021037 | -0.048845 | 0.0 | 0.0 | -0.041524 | -0.043018 | -0.006016 | -0.058880 | -0.048025 | -0.053213 | -0.036596 | -0.081737 | 0.002303 | 0.004758 | 0.010354 | 0.001378 | 0.002047 | 0.003490 | -0.017953 | 0.018382 | -0.055324 | -0.027244 | -0.019638 | 0.071633 | -0.026239 | -0.045662 | -0.049276 | -0.025011 | -0.007563 | -0.016594 | -0.023095 | 0.010499 | -0.009022 | 0.004386 | -5.017507e-03 | 0.007362 | 3.295975e-17 | -0.015316 | 0.003753 | -0.001178 | 0.007182 | -0.059731 | -0.065739 | -0.016031 |
| 2000-01-06 | -0.014901 | -0.018433 | -0.032261 | 0.017488 | 0.000000 | -0.008876 | -0.019495 | -0.055583 | 0.0 | 0.0 | -0.053399 | -0.052706 | -0.012579 | -0.066145 | -0.048025 | -0.064771 | -0.076551 | -0.126826 | 0.001611 | 0.003015 | 0.006800 | 0.001870 | 0.001949 | 0.003490 | -0.010969 | 0.022851 | -0.059636 | -0.032569 | -0.023716 | 0.058801 | -0.025193 | -0.037365 | -0.069144 | -0.031424 | -0.011659 | -0.023237 | -0.020821 | 0.012306 | 0.006801 | 0.011937 | 1.413800e-16 | 0.003674 | 2.290204e-03 | -0.012167 | -0.001889 | -0.014783 | -0.004760 | -0.074597 | -0.058878 | -0.026066 |
| 2000-01-07 | -0.013314 | -0.016786 | -0.030383 | 0.012044 | -0.003802 | -0.005908 | -0.014391 | -0.016644 | 0.0 | 0.0 | -0.051391 | -0.002766 | -0.033208 | -0.048580 | -0.034360 | -0.031181 | -0.061580 | -0.108566 | 0.000874 | 0.000811 | 0.002986 | 0.002139 | -0.000097 | -0.001257 | -0.020374 | 0.010918 | -0.082458 | -0.055469 | -0.047077 | 0.069330 | -0.023414 | -0.042801 | -0.064069 | -0.011863 | -0.010489 | -0.032734 | -0.023095 | 0.020434 | 0.018156 | 0.017712 | -1.299355e-02 | -0.012151 | -2.284971e-03 | -0.018976 | -0.010564 | -0.014188 | -0.018904 | -0.097974 | -0.070954 | -0.061528 |
| 2000-01-10 | -0.011824 | -0.014073 | -0.029339 | 0.010925 | -0.002061 | -0.005908 | -0.011585 | -0.006254 | 0.0 | 0.0 | -0.033931 | 0.012392 | -0.035470 | -0.033412 | -0.032734 | -0.021517 | -0.061580 | -0.067519 | 0.001980 | 0.003015 | 0.005436 | -0.004205 | -0.000292 | -0.002030 | -0.017256 | 0.010210 | -0.055324 | -0.037065 | -0.047511 | 0.049735 | -0.024129 | -0.041880 | -0.057794 | 0.006113 | -0.019311 | -0.038132 | -0.033485 | 0.020879 | 0.016743 | 0.016847 | -1.992087e-02 | -0.019371 | -2.284971e-03 | -0.007951 | 0.002478 | -0.012401 | -0.002383 | -0.068624 | -0.069252 | -0.054088 |
# Step 2: Calculate daily log returns from cumulative log returns
daily_log_returns_SMA = combined_df_SMA_cleaned.diff().fillna(0)
# Initialize a DataFrame to hold the adjusted weights
adjusted_weights = pd.DataFrame(index=daily_log_returns_SMA.index, columns=daily_log_returns_SMA.columns)
# Calculate weights dynamically each day using cumulative returns to check asset activity
for date, returns in combined_df_SMA_cleaned.iterrows():
# Use the cumulative returns to determine active assets
active_assets = returns[returns != 0].count() # Count non-zero cumulative returns for the day
if active_assets > 0:
daily_weights = 1 / active_assets # Equal weight divided by the number of active assets
else:
daily_weights = 0 # No active assets to invest in
adjusted_weights.loc[date] = daily_weights
# Save the adjusted weights to an Excel file
adjusted_weights.to_excel('rebalanced_weights_equalweighted_SMA.xlsx')
# Step 3: Calculate portfolio returns using the dynamically adjusted weights
portfolio_SMA_log_returns = (daily_log_returns_SMA * adjusted_weights).sum(axis=1)
portfolio_SMA_simple_returns = np.exp(portfolio_SMA_log_returns) - 1
portfolio_SMA_cumulative_simple_returns = (1 + portfolio_SMA_simple_returns).cumprod() - 1
# Step 4: Plot the performance
trace = go.Scatter(x=combined_df_SMA_cleaned.index, y=portfolio_SMA_cumulative_simple_returns, mode='lines', name='Cumulative Simple Returns')
layout = go.Layout(title='Equal-weighted Portfolio SMA - Adjusted Over Time', xaxis=dict(title='Days'), yaxis=dict(title='Simple Return'))
fig = go.Figure(data=[trace], layout=layout)
fig.show()
<ipython-input-50-893fd8db71bd>:18: UserWarning: Pandas requires version '1.4.3' or newer of 'xlsxwriter' (version '1.3.8' currently installed).
for header, df in strategy_SMA_bands.items():
print(f"strategy_SMA_bands['{header}']")
print('-' * 40)
print('Nr. of Futures: ' + str(len(strategy_SMA_bands)))
strategy_SMA_bands['USD Future'] strategy_SMA_bands['EUR Future (USD)'] strategy_SMA_bands['JPY Future (USD)'] strategy_SMA_bands['GBP Future (USD)'] strategy_SMA_bands['GBP Future (EUR)'] strategy_SMA_bands['CAD Future (USD)'] strategy_SMA_bands['CHF Future (USD)'] strategy_SMA_bands['S&P 500'] strategy_SMA_bands['Nasdaq 100'] strategy_SMA_bands['S&P Canada 60'] strategy_SMA_bands['FTSE 100'] strategy_SMA_bands['DAX'] strategy_SMA_bands['SMI'] strategy_SMA_bands['CAC - 40'] strategy_SMA_bands['IBEX 35'] strategy_SMA_bands['Euro Stoxx 50'] strategy_SMA_bands['Nikkei 225'] strategy_SMA_bands['Hang Seng Index'] strategy_SMA_bands['US 2-year'] strategy_SMA_bands['US 5-year'] strategy_SMA_bands['US 10-year'] strategy_SMA_bands['Long Gilt (10 year)'] strategy_SMA_bands['Euro-Schatz-Futures (2 year)'] strategy_SMA_bands['Euro-Bobl-Future (5 year)'] strategy_SMA_bands['Euro-Bund-Future (10 year)'] strategy_SMA_bands['Euro-Buxl-Future (30 year)'] strategy_SMA_bands['Brent Crude Oil'] strategy_SMA_bands['WTI Crude Oil'] strategy_SMA_bands['Heating Oil'] strategy_SMA_bands['Natural Gas'] strategy_SMA_bands['Gold'] strategy_SMA_bands['Silver'] strategy_SMA_bands['Platinum'] strategy_SMA_bands['Palladium'] strategy_SMA_bands['Copper'] strategy_SMA_bands['Nickel'] strategy_SMA_bands['Zinc'] strategy_SMA_bands['Lean hogs'] strategy_SMA_bands['Live cattle'] strategy_SMA_bands['Feeder cattle'] strategy_SMA_bands['Wheat'] strategy_SMA_bands['Corn'] strategy_SMA_bands['Oat'] strategy_SMA_bands['Soybeans'] strategy_SMA_bands['Soybean oil'] strategy_SMA_bands['Frozen orange juice'] strategy_SMA_bands['Cocoa'] strategy_SMA_bands['Coffee'] strategy_SMA_bands['Sugar No.11'] strategy_SMA_bands['Cotton No.2'] ---------------------------------------- Nr. of Futures: 50
#start_date = '2000-01-01'
# List to hold the data series
data_series_list_SMA_bands = []
# Extract 'Cumulative_Log_Returns' and rename it uniquely
for name, df in strategy_SMA_bands.items():
if 'Cumulative_Log_Returns' in df.columns:
# Filter the DataFrame to only include data from the start_date onwards
filtered_df = df[df.index >= pd.to_datetime(start_date)]
# Rename the series with its asset name and add to the list
series = filtered_df['Cumulative_Log_Returns'].rename(name)
data_series_list_SMA_bands.append(series)
# Combine all the series into a single DataFrame
combined_df_SMA_bands = pd.concat(data_series_list_SMA_bands, axis=1, join='outer')
# Forward fill missing values
combined_df_SMA_bands_filled = combined_df_SMA_bands.ffill()
# Drop rows where any NaN values still exist (likely at the start)
combined_df_SMA_bands_cleaned = combined_df_SMA_bands_filled.dropna()
pd.set_option('display.max_columns', None)
combined_df_SMA_bands_cleaned.head()
| USD Future | EUR Future (USD) | JPY Future (USD) | GBP Future (USD) | GBP Future (EUR) | CAD Future (USD) | CHF Future (USD) | S&P 500 | Nasdaq 100 | S&P Canada 60 | FTSE 100 | DAX | SMI | CAC - 40 | IBEX 35 | Euro Stoxx 50 | Nikkei 225 | Hang Seng Index | US 2-year | US 5-year | US 10-year | Long Gilt (10 year) | Euro-Schatz-Futures (2 year) | Euro-Bobl-Future (5 year) | Euro-Bund-Future (10 year) | Euro-Buxl-Future (30 year) | Brent Crude Oil | WTI Crude Oil | Heating Oil | Natural Gas | Gold | Silver | Platinum | Palladium | Copper | Nickel | Zinc | Lean hogs | Live cattle | Feeder cattle | Wheat | Corn | Oat | Soybeans | Soybean oil | Frozen orange juice | Cocoa | Coffee | Sugar No.11 | Cotton No.2 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Date | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 2000-01-04 | -0.015201 | -0.018726 | -0.010262 | -0.001316 | 0.000000 | -0.002950 | -0.019341 | -0.050080 | 0.0 | 0.0 | -0.024268 | -0.031807 | -0.015051 | -0.026219 | -0.025887 | -0.033067 | 0.002820 | 0.000763 | -0.001244 | 0.000927 | 0.002986 | -0.001479 | 0.0 | 0.003393 | -0.016893 | 0.013577 | -0.027977 | -0.001862 | -0.001331 | 0.067950 | -0.020597 | -0.014430 | -0.020354 | -0.016386 | -0.017536 | -0.015752 | -0.018352 | 0.020434 | -0.007572 | 0.004970 | 5.042964e-03 | 0.007362 | 2.290204e-03 | -0.003716 | 0.012554 | -0.024958 | 0.000955 | -0.079745 | -0.058878 | 0.000196 |
| 2000-01-05 | -0.015201 | -0.020362 | -0.021354 | 0.001642 | 0.000000 | -0.001474 | -0.021037 | -0.048845 | 0.0 | 0.0 | -0.041524 | -0.043018 | -0.015051 | -0.058880 | -0.048025 | -0.053213 | -0.036596 | -0.081737 | 0.000092 | 0.004758 | 0.010354 | 0.001378 | 0.0 | 0.003490 | -0.017953 | 0.018382 | -0.055324 | -0.027244 | -0.019638 | 0.071633 | -0.020597 | -0.045662 | -0.049276 | -0.025011 | -0.007563 | -0.016594 | -0.023095 | 0.010499 | -0.009022 | 0.004386 | -5.017507e-03 | 0.007362 | 3.295975e-17 | -0.015316 | 0.003753 | -0.001178 | 0.007182 | -0.059731 | -0.065739 | -0.016031 |
| 2000-01-06 | -0.015201 | -0.018433 | -0.032261 | 0.004984 | 0.000000 | -0.008876 | -0.019495 | -0.055583 | 0.0 | 0.0 | -0.053399 | -0.052706 | -0.021614 | -0.066145 | -0.048025 | -0.064771 | -0.076551 | -0.126826 | -0.000599 | 0.003015 | 0.006800 | 0.001870 | 0.0 | 0.003490 | -0.010969 | 0.022851 | -0.059636 | -0.032569 | -0.023716 | 0.058801 | -0.020597 | -0.037365 | -0.069144 | -0.031424 | -0.011659 | -0.023237 | -0.020821 | 0.012306 | 0.006801 | 0.011937 | 1.413800e-16 | 0.003674 | 2.290204e-03 | -0.012167 | -0.001889 | -0.014783 | -0.004760 | -0.074597 | -0.058878 | -0.026066 |
| 2000-01-07 | -0.015201 | -0.016786 | -0.030383 | -0.000460 | -0.003802 | -0.008876 | -0.014391 | -0.016644 | 0.0 | 0.0 | -0.051391 | -0.002766 | -0.021614 | -0.048580 | -0.034360 | -0.031181 | -0.061580 | -0.108566 | -0.001336 | 0.000811 | 0.002986 | 0.002139 | 0.0 | -0.001257 | -0.020374 | 0.010918 | -0.082458 | -0.055469 | -0.047077 | 0.069330 | -0.020597 | -0.042801 | -0.064069 | -0.011863 | -0.010489 | -0.032734 | -0.023095 | 0.020434 | 0.018156 | 0.017712 | -1.299355e-02 | -0.012151 | -2.284971e-03 | -0.018976 | -0.010564 | -0.014188 | -0.018904 | -0.097974 | -0.070954 | -0.061528 |
| 2000-01-10 | -0.015201 | -0.014073 | -0.029339 | -0.001579 | -0.002061 | -0.008876 | -0.011585 | -0.006254 | 0.0 | 0.0 | -0.033931 | 0.012392 | -0.023876 | -0.033412 | -0.032734 | -0.021517 | -0.061580 | -0.067519 | -0.000230 | 0.003015 | 0.005436 | -0.004205 | 0.0 | -0.002030 | -0.017256 | 0.010210 | -0.055324 | -0.037065 | -0.047511 | 0.049735 | -0.020597 | -0.041880 | -0.057794 | 0.006113 | -0.019311 | -0.038132 | -0.033485 | 0.020879 | 0.016743 | 0.016847 | -1.992087e-02 | -0.019371 | -2.284971e-03 | -0.007951 | 0.002478 | -0.012401 | -0.002383 | -0.068624 | -0.069252 | -0.054088 |
# Step 2: Calculate daily log returns from cumulative log returns
daily_log_returns_SMA_bands = combined_df_SMA_bands_cleaned.diff().fillna(0)
# Initialize a DataFrame to hold the adjusted weights
adjusted_weights = pd.DataFrame(index=daily_log_returns_SMA_bands.index, columns=daily_log_returns_SMA_bands.columns)
# Calculate weights dynamically each day using cumulative returns to check asset activity
for date, returns in combined_df_SMA_bands_cleaned.iterrows():
# Use the cumulative returns to determine active assets
active_assets = returns[returns != 0].count() # Count non-zero cumulative returns for the day
if active_assets > 0:
daily_weights = 1 / active_assets # Equal weight divided by the number of active assets
else:
daily_weights = 0 # No active assets to invest in
adjusted_weights.loc[date] = daily_weights
# Save the adjusted weights to an Excel file
adjusted_weights.to_excel('rebalanced_weights_equalweighted_SMA_bands.xlsx')
# Step 3: Calculate portfolio returns using the dynamically adjusted weights
portfolio_SMA_bands_log_returns = (daily_log_returns_SMA_bands * adjusted_weights).sum(axis=1)
portfolio_SMA_bands_simple_returns = np.exp(portfolio_SMA_bands_log_returns) - 1
portfolio_SMA_bands_cumulative_simple_returns = (1 + portfolio_SMA_bands_simple_returns).cumprod() - 1
# Step 4: Plot the performance
trace = go.Scatter(x=combined_df_SMA_bands_cleaned.index, y=portfolio_SMA_bands_cumulative_simple_returns, mode='lines', name='Cumulative Simple Returns')
layout = go.Layout(title='Equal-weighted Portfolio SMA with Bands - Adjusted Over Time', xaxis=dict(title='Days'), yaxis=dict(title='Simple Return'))
fig = go.Figure(data=[trace], layout=layout)
fig.show()
<ipython-input-54-956381f5dd7a>:18: UserWarning: Pandas requires version '1.4.3' or newer of 'xlsxwriter' (version '1.3.8' currently installed).
for header, df in strategy_TSMOM.items():
print(f"strategy_TSMOM['{header}']")
print('-' * 40)
print('Nr. of Futures: ' + str(len(strategy_TSMOM)))
strategy_TSMOM['USD Future'] strategy_TSMOM['EUR Future (USD)'] strategy_TSMOM['JPY Future (USD)'] strategy_TSMOM['GBP Future (USD)'] strategy_TSMOM['GBP Future (EUR)'] strategy_TSMOM['CAD Future (USD)'] strategy_TSMOM['CHF Future (USD)'] strategy_TSMOM['S&P 500'] strategy_TSMOM['Nasdaq 100'] strategy_TSMOM['S&P Canada 60'] strategy_TSMOM['FTSE 100'] strategy_TSMOM['DAX'] strategy_TSMOM['SMI'] strategy_TSMOM['CAC - 40'] strategy_TSMOM['IBEX 35'] strategy_TSMOM['Euro Stoxx 50'] strategy_TSMOM['Nikkei 225'] strategy_TSMOM['Hang Seng Index'] strategy_TSMOM['US 2-year'] strategy_TSMOM['US 5-year'] strategy_TSMOM['US 10-year'] strategy_TSMOM['Long Gilt (10 year)'] strategy_TSMOM['Euro-Schatz-Futures (2 year)'] strategy_TSMOM['Euro-Bobl-Future (5 year)'] strategy_TSMOM['Euro-Bund-Future (10 year)'] strategy_TSMOM['Euro-Buxl-Future (30 year)'] strategy_TSMOM['Brent Crude Oil'] strategy_TSMOM['WTI Crude Oil'] strategy_TSMOM['Heating Oil'] strategy_TSMOM['Natural Gas'] strategy_TSMOM['Gold'] strategy_TSMOM['Silver'] strategy_TSMOM['Platinum'] strategy_TSMOM['Palladium'] strategy_TSMOM['Copper'] strategy_TSMOM['Nickel'] strategy_TSMOM['Zinc'] strategy_TSMOM['Lean hogs'] strategy_TSMOM['Live cattle'] strategy_TSMOM['Feeder cattle'] strategy_TSMOM['Wheat'] strategy_TSMOM['Corn'] strategy_TSMOM['Oat'] strategy_TSMOM['Soybeans'] strategy_TSMOM['Soybean oil'] strategy_TSMOM['Frozen orange juice'] strategy_TSMOM['Cocoa'] strategy_TSMOM['Coffee'] strategy_TSMOM['Sugar No.11'] strategy_TSMOM['Cotton No.2'] ---------------------------------------- Nr. of Futures: 50
#start_date = '2000-01-01'
# List to hold the data series
data_series_list_TSMOM = []
# Extract 'Cumulative_Log_Returns' and rename it uniquely
for name, df in strategy_TSMOM.items():
if 'Cumulative_Log_Returns' in df.columns:
# Filter the DataFrame to only include data from the start_date onwards
filtered_df = df[df.index >= pd.to_datetime(start_date)]
# Rename the series with its asset name and add to the list
series = filtered_df['Cumulative_Log_Returns'].rename(name)
data_series_list_TSMOM.append(series)
# Combine all the series into a single DataFrame
combined_df_TSMOM = pd.concat(data_series_list_TSMOM, axis=1, join='outer')
# Forward fill missing values
combined_df_TSMOM_filled = combined_df_TSMOM.ffill()
# Drop rows where any NaN values still exist (likely at the start)
combined_df_TSMOM_cleaned = combined_df_TSMOM_filled.dropna()
pd.set_option('display.max_columns', None)
combined_df_TSMOM_cleaned.head()
| USD Future | EUR Future (USD) | JPY Future (USD) | GBP Future (USD) | GBP Future (EUR) | CAD Future (USD) | CHF Future (USD) | S&P 500 | Nasdaq 100 | S&P Canada 60 | FTSE 100 | DAX | SMI | CAC - 40 | IBEX 35 | Euro Stoxx 50 | Nikkei 225 | Hang Seng Index | US 2-year | US 5-year | US 10-year | Long Gilt (10 year) | Euro-Schatz-Futures (2 year) | Euro-Bobl-Future (5 year) | Euro-Bund-Future (10 year) | Euro-Buxl-Future (30 year) | Brent Crude Oil | WTI Crude Oil | Heating Oil | Natural Gas | Gold | Silver | Platinum | Palladium | Copper | Nickel | Zinc | Lean hogs | Live cattle | Feeder cattle | Wheat | Corn | Oat | Soybeans | Soybean oil | Frozen orange juice | Cocoa | Coffee | Sugar No.11 | Cotton No.2 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Date | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 2000-01-04 | -0.013101 | -0.018726 | -0.010262 | -0.011188 | 0.0 | -0.002950 | -0.019341 | -0.050080 | 0.0 | 0.0 | 0.000000 | -0.015641 | 0.015051 | -0.026219 | 0.000000 | -0.029524 | 0.0 | 0.0 | 0.000000 | 0.000000e+00 | 0.000000 | -0.001479 | -0.000195 | 0.000000 | -0.008789 | 0.013577 | 0.000000e+00 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | -0.015752 | -0.018352 | -0.006274 | -0.009009 | -0.001166 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.024958 | 0.000000 | 0.000000 | 0.000000 | 0.000196 |
| 2000-01-05 | -0.013597 | -0.020362 | -0.021354 | -0.014146 | 0.0 | -0.001474 | -0.021037 | -0.048845 | 0.0 | 0.0 | -0.017256 | -0.026852 | 0.024086 | -0.058880 | 0.000000 | -0.049670 | 0.0 | 0.0 | 0.000000 | 0.000000e+00 | 0.000000 | 0.001378 | -0.000195 | 0.000097 | -0.009848 | 0.018382 | 0.000000e+00 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | -0.016594 | -0.023095 | -0.016209 | -0.010459 | -0.001749 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.001178 | 0.000000 | 0.000000 | 0.000000 | -0.016031 |
| 2000-01-06 | -0.010701 | -0.018433 | -0.032261 | -0.017488 | 0.0 | -0.008876 | -0.019495 | -0.055583 | 0.0 | 0.0 | -0.029131 | -0.036540 | 0.017523 | -0.066145 | 0.000000 | -0.061229 | 0.0 | 0.0 | 0.000000 | 0.000000e+00 | -0.003554 | 0.001870 | -0.000293 | 0.000097 | -0.002864 | 0.022851 | -4.311384e-03 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | -0.023237 | -0.020821 | -0.014402 | 0.005363 | 0.005801 | 0.005018 | -0.003688 | 0.000000 | 0.000000 | 0.000000 | 0.014783 | 0.000000 | 0.000000 | 0.000000 | -0.026066 |
| 2000-01-07 | -0.009114 | -0.016786 | -0.030383 | -0.012044 | 0.0 | -0.005908 | -0.014391 | -0.016644 | 0.0 | 0.0 | -0.027124 | 0.013400 | -0.003107 | -0.048580 | 0.000000 | -0.027638 | 0.0 | 0.0 | -0.000737 | -2.204049e-03 | -0.007368 | 0.002139 | -0.002339 | -0.004651 | -0.012269 | 0.010918 | -2.713345e-02 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | -0.032734 | -0.023095 | -0.006274 | 0.016719 | 0.011576 | -0.007976 | -0.019513 | -0.004575 | -0.006809 | -0.008676 | 0.014188 | -0.014145 | 0.023378 | -0.012076 | -0.061528 |
| 2000-01-10 | -0.007624 | -0.014073 | -0.029339 | -0.010925 | 0.0 | -0.005908 | -0.011585 | -0.006254 | 0.0 | 0.0 | -0.009663 | 0.028558 | -0.000845 | -0.033412 | -0.001626 | -0.017974 | 0.0 | 0.0 | 0.000369 | 4.466913e-17 | -0.004918 | -0.004205 | -0.002534 | -0.005424 | -0.009151 | 0.010210 | 3.122502e-17 | 0.018405 | -0.000434 | -0.019595 | 0.000715 | 0.0 | 0.0 | 0.0 | 0.0 | -0.038132 | -0.033485 | -0.005829 | 0.015306 | 0.010712 | -0.014903 | -0.026733 | -0.004575 | 0.004216 | 0.004366 | 0.012401 | 0.002377 | -0.005973 | -0.010374 | -0.054088 |
# Step 2: Calculate daily log returns from cumulative log returns
daily_log_returns_TSMOM = combined_df_TSMOM_cleaned.diff().fillna(0)
# Initialize a DataFrame to hold the adjusted weights
adjusted_weights = pd.DataFrame(index=daily_log_returns_TSMOM.index, columns=daily_log_returns_TSMOM.columns)
# Calculate weights dynamically each day using cumulative returns to check asset activity
for date, returns in combined_df_TSMOM_cleaned.iterrows():
# Use the cumulative returns to determine active assets
active_assets = returns[returns != 0].count() # Count non-zero cumulative returns for the day
if active_assets > 0:
daily_weights = 1 / active_assets # Equal weight divided by the number of active assets
else:
daily_weights = 0 # No active assets to invest in
adjusted_weights.loc[date] = daily_weights
# Save the adjusted weights to an Excel file
adjusted_weights.to_excel('rebalanced_weights_equalweighted_TSMOM.xlsx')
# Step 3: Calculate portfolio returns using the dynamically adjusted weights
portfolio_TSMOM_log_returns = (daily_log_returns_TSMOM * adjusted_weights).sum(axis=1)
portfolio_TSMOM_simple_returns = np.exp(portfolio_TSMOM_log_returns) - 1
portfolio_TSMOM_cumulative_simple_returns = (1 + portfolio_TSMOM_simple_returns).cumprod() - 1
# Step 4: Plot the performance
trace = go.Scatter(x=combined_df_TSMOM_cleaned.index, y=portfolio_TSMOM_cumulative_simple_returns, mode='lines', name='Cumulative Simple Returns')
layout = go.Layout(title='Equal-weighted Portfolio TSMOM - Adjusted Over Time', xaxis=dict(title='Days'), yaxis=dict(title='Simple Return'))
fig = go.Figure(data=[trace], layout=layout)
fig.show()
<ipython-input-58-75b0ada3f235>:18: UserWarning: Pandas requires version '1.4.3' or newer of 'xlsxwriter' (version '1.3.8' currently installed).
for header, df in strategy_RAMOM.items():
print(f"strategy_RAMOM['{header}']")
print('-' * 40)
print('Nr. of Futures: ' + str(len(strategy_RAMOM)))
strategy_RAMOM['USD Future'] strategy_RAMOM['EUR Future (USD)'] strategy_RAMOM['JPY Future (USD)'] strategy_RAMOM['GBP Future (USD)'] strategy_RAMOM['GBP Future (EUR)'] strategy_RAMOM['CAD Future (USD)'] strategy_RAMOM['CHF Future (USD)'] strategy_RAMOM['S&P 500'] strategy_RAMOM['Nasdaq 100'] strategy_RAMOM['S&P Canada 60'] strategy_RAMOM['FTSE 100'] strategy_RAMOM['DAX'] strategy_RAMOM['SMI'] strategy_RAMOM['CAC - 40'] strategy_RAMOM['IBEX 35'] strategy_RAMOM['Euro Stoxx 50'] strategy_RAMOM['Nikkei 225'] strategy_RAMOM['Hang Seng Index'] strategy_RAMOM['US 2-year'] strategy_RAMOM['US 5-year'] strategy_RAMOM['US 10-year'] strategy_RAMOM['Long Gilt (10 year)'] strategy_RAMOM['Euro-Schatz-Futures (2 year)'] strategy_RAMOM['Euro-Bobl-Future (5 year)'] strategy_RAMOM['Euro-Bund-Future (10 year)'] strategy_RAMOM['Euro-Buxl-Future (30 year)'] strategy_RAMOM['Brent Crude Oil'] strategy_RAMOM['WTI Crude Oil'] strategy_RAMOM['Heating Oil'] strategy_RAMOM['Natural Gas'] strategy_RAMOM['Gold'] strategy_RAMOM['Silver'] strategy_RAMOM['Platinum'] strategy_RAMOM['Palladium'] strategy_RAMOM['Copper'] strategy_RAMOM['Nickel'] strategy_RAMOM['Zinc'] strategy_RAMOM['Lean hogs'] strategy_RAMOM['Live cattle'] strategy_RAMOM['Feeder cattle'] strategy_RAMOM['Wheat'] strategy_RAMOM['Corn'] strategy_RAMOM['Oat'] strategy_RAMOM['Soybeans'] strategy_RAMOM['Soybean oil'] strategy_RAMOM['Frozen orange juice'] strategy_RAMOM['Cocoa'] strategy_RAMOM['Coffee'] strategy_RAMOM['Sugar No.11'] strategy_RAMOM['Cotton No.2'] ---------------------------------------- Nr. of Futures: 50
#start_date = '2000-01-01'
# List to hold the data series
data_series_list_RAMOM = []
# Extract 'Cumulative_Log_Returns' and rename it uniquely
for name, df in strategy_RAMOM.items():
if 'Cumulative_Log_Returns' in df.columns:
# Filter the DataFrame to only include data from the start_date onwards
filtered_df = df[df.index >= pd.to_datetime(start_date)]
# Rename the series with its asset name and add to the list
series = filtered_df['Cumulative_Log_Returns'].rename(name)
data_series_list_RAMOM.append(series)
# Combine all the series into a single DataFrame
combined_df_RAMOM = pd.concat(data_series_list_RAMOM, axis=1, join='outer')
# Forward fill missing values
combined_df_RAMOM_filled = combined_df_RAMOM.ffill()
# Drop rows where any NaN values still exist (likely at the start)
combined_df_RAMOM_cleaned = combined_df_RAMOM_filled.dropna()
pd.set_option('display.max_columns', None)
combined_df_RAMOM_cleaned.head()
| USD Future | EUR Future (USD) | JPY Future (USD) | GBP Future (USD) | GBP Future (EUR) | CAD Future (USD) | CHF Future (USD) | S&P 500 | Nasdaq 100 | S&P Canada 60 | FTSE 100 | DAX | SMI | CAC - 40 | IBEX 35 | Euro Stoxx 50 | Nikkei 225 | Hang Seng Index | US 2-year | US 5-year | US 10-year | Long Gilt (10 year) | Euro-Schatz-Futures (2 year) | Euro-Bobl-Future (5 year) | Euro-Bund-Future (10 year) | Euro-Buxl-Future (30 year) | Brent Crude Oil | WTI Crude Oil | Heating Oil | Natural Gas | Gold | Silver | Platinum | Palladium | Copper | Nickel | Zinc | Lean hogs | Live cattle | Feeder cattle | Wheat | Corn | Oat | Soybeans | Soybean oil | Frozen orange juice | Cocoa | Coffee | Sugar No.11 | Cotton No.2 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Date | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 2000-01-04 | -0.013101 | -0.018726 | -0.010262 | -0.011188 | -0.007459 | 0.002950 | -0.019341 | -0.050080 | -0.053766 | -0.024980 | -0.024268 | -0.031807 | 0.015051 | -0.026219 | -0.025887 | -0.033067 | 0.002820 | 0.000763 | 0.000966 | 0.000927 | 0.002986 | -0.001479 | 0.002047 | 0.003393 | -0.016893 | 0.013577 | -0.027977 | -0.001862 | -0.001331 | 0.067950 | 0.020597 | -0.014430 | -0.020354 | -0.016386 | -0.017536 | -0.015752 | -0.018352 | -0.020434 | -0.010446 | 0.004970 | 5.042964e-03 | 0.007362 | 2.290204e-03 | -0.003716 | 0.012554 | 0.024958 | 0.000955 | -0.079745 | 0.058878 | 0.000196 |
| 2000-01-05 | -0.013597 | -0.020362 | -0.021354 | -0.014146 | -0.006201 | 0.001474 | -0.021037 | -0.048845 | -0.066495 | -0.038664 | -0.041524 | -0.043018 | 0.024086 | -0.058880 | -0.048025 | -0.053213 | -0.036596 | -0.081737 | 0.002303 | 0.004758 | 0.010354 | 0.001378 | 0.002047 | 0.003490 | -0.017953 | 0.018382 | -0.055324 | -0.027244 | -0.019638 | 0.071633 | 0.026239 | -0.045662 | -0.049276 | -0.025011 | -0.007563 | -0.016594 | -0.023095 | -0.010499 | -0.008996 | 0.004386 | -5.017507e-03 | 0.007362 | 3.295975e-17 | -0.015316 | 0.003753 | 0.001178 | 0.007182 | -0.059731 | 0.052017 | -0.016031 |
| 2000-01-06 | -0.010701 | -0.018433 | -0.032261 | -0.017488 | -0.000962 | 0.008876 | -0.019495 | -0.055583 | -0.125119 | -0.052707 | -0.053399 | -0.052706 | 0.017523 | -0.066145 | -0.048025 | -0.064771 | -0.076551 | -0.126826 | 0.001611 | 0.003015 | 0.006800 | 0.001870 | 0.001949 | 0.003490 | -0.010969 | 0.022851 | -0.059636 | -0.032569 | -0.023716 | 0.058801 | 0.025193 | -0.053959 | -0.069144 | -0.031424 | -0.011659 | -0.023237 | -0.020821 | -0.012306 | -0.024818 | 0.011937 | 1.413800e-16 | 0.003674 | 2.290204e-03 | -0.012167 | -0.001889 | 0.014783 | -0.004760 | -0.074597 | 0.058878 | -0.026066 |
| 2000-01-07 | -0.009114 | -0.016786 | -0.030383 | -0.022933 | -0.004764 | 0.011843 | -0.014391 | -0.016644 | -0.052501 | -0.009351 | -0.051391 | -0.002766 | -0.003107 | -0.048580 | -0.034360 | -0.031181 | -0.061580 | -0.108566 | 0.000874 | 0.000811 | 0.002986 | 0.002139 | -0.000097 | -0.001257 | -0.020374 | 0.010918 | -0.082458 | -0.055469 | -0.047077 | 0.069330 | 0.023414 | -0.048522 | -0.064069 | -0.011863 | -0.010489 | -0.032734 | -0.023095 | -0.020434 | -0.036174 | 0.017712 | -1.299355e-02 | 0.019500 | -2.284971e-03 | -0.018976 | -0.010564 | 0.014188 | -0.018904 | -0.051219 | 0.046802 | -0.061528 |
| 2000-01-10 | -0.010604 | -0.014073 | -0.029339 | -0.024052 | -0.003023 | 0.011843 | -0.011585 | -0.006254 | 0.004252 | 0.012042 | -0.033931 | 0.012392 | -0.000845 | -0.033412 | -0.032734 | -0.021517 | -0.061580 | -0.067519 | 0.001980 | 0.003015 | 0.005436 | -0.004205 | -0.000292 | -0.002030 | -0.017256 | 0.010210 | -0.055324 | -0.037065 | -0.047511 | 0.049735 | 0.024129 | -0.049443 | -0.057794 | 0.006113 | -0.019311 | -0.038132 | -0.033485 | -0.020879 | -0.037588 | 0.016847 | -1.992087e-02 | 0.026720 | -2.284971e-03 | -0.007951 | 0.002478 | 0.012401 | -0.002383 | -0.080570 | 0.048504 | -0.054088 |
# Step 2: Calculate daily log returns from cumulative log returns
daily_log_returns_RAMOM = combined_df_RAMOM_cleaned.diff().fillna(0)
# Initialize a DataFrame to hold the adjusted weights
adjusted_weights = pd.DataFrame(index=daily_log_returns_RAMOM.index, columns=daily_log_returns_RAMOM.columns)
# Calculate weights dynamically each day using cumulative returns to check asset activity
for date, returns in combined_df_RAMOM_cleaned.iterrows():
# Use the cumulative returns to determine active assets
active_assets = returns[returns != 0].count() # Count non-zero cumulative returns for the day
if active_assets > 0:
daily_weights = 1 / active_assets # Equal weight divided by the number of active assets
else:
daily_weights = 0 # No active assets to invest in
adjusted_weights.loc[date] = daily_weights
# Save the adjusted weights to an Excel file
adjusted_weights.to_excel('rebalanced_weights_equalweighted_RAMOM.xlsx')
# Step 3: Calculate portfolio returns using the dynamically adjusted weights
portfolio_RAMOM_log_returns = (daily_log_returns_RAMOM * adjusted_weights).sum(axis=1)
portfolio_RAMOM_simple_returns = np.exp(portfolio_RAMOM_log_returns) - 1
portfolio_RAMOM_cumulative_simple_returns = (1 + portfolio_RAMOM_simple_returns).cumprod() - 1
# Step 4: Plot the performance
trace = go.Scatter(x=combined_df_RAMOM_cleaned.index, y=portfolio_RAMOM_cumulative_simple_returns, mode='lines', name='Cumulative Simple Returns')
layout = go.Layout(title='Equal-weighted Portfolio RAMOM - Adjusted Over Time', xaxis=dict(title='Days'), yaxis=dict(title='Simple Return'))
fig = go.Figure(data=[trace], layout=layout)
fig.show()
<ipython-input-62-547a37fb0648>:18: UserWarning: Pandas requires version '1.4.3' or newer of 'xlsxwriter' (version '1.3.8' currently installed).
for header, df in strategy_kalman.items():
print(f"strategy_kalman['{header}']")
print('-' * 40)
print('Nr. of Futures: ' + str(len(strategy_kalman)))
strategy_kalman['USD Future'] strategy_kalman['EUR Future (USD)'] strategy_kalman['JPY Future (USD)'] strategy_kalman['GBP Future (USD)'] strategy_kalman['GBP Future (EUR)'] strategy_kalman['CAD Future (USD)'] strategy_kalman['CHF Future (USD)'] strategy_kalman['S&P 500'] strategy_kalman['Nasdaq 100'] strategy_kalman['S&P Canada 60'] strategy_kalman['FTSE 100'] strategy_kalman['DAX'] strategy_kalman['SMI'] strategy_kalman['CAC - 40'] strategy_kalman['IBEX 35'] strategy_kalman['Euro Stoxx 50'] strategy_kalman['Nikkei 225'] strategy_kalman['Hang Seng Index'] strategy_kalman['US 2-year'] strategy_kalman['US 5-year'] strategy_kalman['US 10-year'] strategy_kalman['Long Gilt (10 year)'] strategy_kalman['Euro-Schatz-Futures (2 year)'] strategy_kalman['Euro-Bobl-Future (5 year)'] strategy_kalman['Euro-Bund-Future (10 year)'] strategy_kalman['Euro-Buxl-Future (30 year)'] strategy_kalman['Brent Crude Oil'] strategy_kalman['WTI Crude Oil'] strategy_kalman['Heating Oil'] strategy_kalman['Natural Gas'] strategy_kalman['Gold'] strategy_kalman['Silver'] strategy_kalman['Platinum'] strategy_kalman['Palladium'] strategy_kalman['Copper'] strategy_kalman['Nickel'] strategy_kalman['Zinc'] strategy_kalman['Lean hogs'] strategy_kalman['Live cattle'] strategy_kalman['Feeder cattle'] strategy_kalman['Wheat'] strategy_kalman['Corn'] strategy_kalman['Oat'] strategy_kalman['Soybeans'] strategy_kalman['Soybean oil'] strategy_kalman['Frozen orange juice'] strategy_kalman['Cocoa'] strategy_kalman['Coffee'] strategy_kalman['Sugar No.11'] strategy_kalman['Cotton No.2'] ---------------------------------------- Nr. of Futures: 50
#start_date = '2000-01-01'
# List to hold the data series
data_series_list_kalman = []
# Extract 'Cumulative_Log_Returns' and rename it uniquely
for name, df in strategy_kalman.items():
if 'Cumulative_Log_Returns' in df.columns:
# Filter the DataFrame to only include data from the start_date onwards
filtered_df = df[df.index >= pd.to_datetime(start_date)]
# Rename the series with its asset name and add to the list
series = filtered_df['Cumulative_Log_Returns'].rename(name)
data_series_list_kalman.append(series)
# Combine all the series into a single DataFrame
combined_df_kalman = pd.concat(data_series_list_kalman, axis=1, join='outer')
# Forward fill missing values
combined_df_kalman_filled = combined_df_kalman.ffill()
# Drop rows where any NaN values still exist (likely at the start)
combined_df_kalman_cleaned = combined_df_kalman_filled.dropna()
pd.set_option('display.max_columns', None)
combined_df_kalman_cleaned.head()
| USD Future | EUR Future (USD) | JPY Future (USD) | GBP Future (USD) | GBP Future (EUR) | CAD Future (USD) | CHF Future (USD) | S&P 500 | Nasdaq 100 | S&P Canada 60 | FTSE 100 | DAX | SMI | CAC - 40 | IBEX 35 | Euro Stoxx 50 | Nikkei 225 | Hang Seng Index | US 2-year | US 5-year | US 10-year | Long Gilt (10 year) | Euro-Schatz-Futures (2 year) | Euro-Bobl-Future (5 year) | Euro-Bund-Future (10 year) | Euro-Buxl-Future (30 year) | Brent Crude Oil | WTI Crude Oil | Heating Oil | Natural Gas | Gold | Silver | Platinum | Palladium | Copper | Nickel | Zinc | Lean hogs | Live cattle | Feeder cattle | Wheat | Corn | Oat | Soybeans | Soybean oil | Frozen orange juice | Cocoa | Coffee | Sugar No.11 | Cotton No.2 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Date | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 2000-01-04 | -0.013101 | -0.018726 | 0.010262 | -0.011188 | -0.007459 | 0.002950 | -0.019341 | -0.026360 | 0.053766 | -0.024980 | 0.024268 | 0.000525 | 0.015051 | 0.026219 | 0.025887 | 0.033067 | -0.002820 | -0.000763 | -0.000966 | -0.000927 | -0.002986 | 0.001479 | -0.002047 | -0.003393 | -0.000684 | -0.013577 | -0.027977 | -0.001862 | -0.001331 | -0.067950 | -0.020597 | 0.014430 | 0.020354 | -0.016386 | 0.017536 | 0.015752 | 0.018352 | -0.020434 | 0.007572 | -0.004970 | 0.003022 | 0.029654 | 0.016105 | 0.026191 | 0.027786 | -0.024958 | -0.000955 | 0.075448 | 0.058878 | 0.000196 |
| 2000-01-05 | -0.013597 | -0.020362 | -0.000830 | -0.014146 | -0.006201 | 0.004426 | -0.021037 | -0.025124 | 0.041037 | -0.038664 | 0.007012 | -0.010686 | 0.006016 | -0.006442 | 0.003749 | 0.012921 | 0.036596 | -0.083263 | 0.000370 | 0.002905 | 0.004382 | -0.001378 | -0.002047 | -0.003490 | -0.001744 | -0.018382 | -0.055324 | -0.027244 | -0.019638 | -0.071633 | -0.026239 | -0.016802 | -0.008567 | -0.025011 | 0.027508 | 0.014910 | 0.013608 | -0.010499 | 0.006121 | -0.004386 | 0.013082 | 0.029654 | 0.013815 | 0.014592 | 0.018985 | -0.001178 | 0.005273 | 0.095461 | 0.065739 | 0.016423 |
| 2000-01-06 | -0.010701 | -0.018433 | -0.011737 | -0.017488 | -0.000962 | 0.011828 | -0.019495 | -0.031863 | -0.017588 | -0.052707 | -0.004863 | -0.020374 | 0.012579 | -0.013708 | 0.003749 | 0.001362 | -0.003358 | -0.128352 | 0.001061 | 0.004648 | 0.007936 | -0.001870 | -0.001949 | -0.003490 | 0.005241 | -0.022851 | -0.059636 | -0.032569 | -0.023716 | -0.058801 | -0.025193 | -0.025100 | -0.028436 | -0.031424 | 0.031604 | 0.008266 | 0.015882 | -0.008692 | 0.021944 | 0.003164 | 0.018100 | 0.025966 | 0.016105 | 0.017741 | 0.013344 | 0.012426 | 0.017215 | 0.110327 | 0.058878 | 0.006389 |
| 2000-01-07 | -0.012288 | -0.020080 | -0.009859 | -0.012044 | 0.002840 | 0.014795 | -0.014391 | 0.007076 | 0.055030 | -0.009351 | -0.002856 | 0.029565 | 0.033208 | 0.003857 | 0.017414 | 0.034953 | 0.011613 | -0.110091 | 0.000324 | 0.002444 | 0.004122 | -0.002139 | 0.000097 | 0.001257 | 0.014646 | -0.010918 | -0.082458 | -0.055469 | -0.047077 | -0.069330 | -0.023414 | -0.019663 | -0.023361 | -0.011863 | 0.032773 | -0.001231 | 0.013608 | -0.000564 | 0.010588 | -0.002611 | 0.031093 | 0.010141 | 0.020680 | 0.010932 | 0.004668 | 0.013021 | 0.003070 | 0.086949 | 0.070954 | -0.029073 |
| 2000-01-10 | -0.013778 | -0.022792 | -0.008815 | -0.013162 | 0.004581 | 0.014795 | -0.017196 | -0.003314 | -0.001723 | -0.030744 | 0.014605 | 0.014407 | 0.035470 | -0.011311 | 0.015788 | 0.025289 | 0.011613 | -0.069044 | 0.001430 | 0.004648 | 0.006572 | 0.004205 | -0.000097 | 0.000484 | 0.017763 | -0.011625 | -0.055324 | -0.037065 | -0.047511 | -0.049735 | -0.022699 | -0.020584 | -0.017085 | -0.029839 | 0.041595 | -0.006629 | 0.003218 | -0.001009 | 0.012002 | -0.001747 | 0.024166 | 0.002921 | 0.020680 | 0.021957 | 0.017710 | 0.014808 | 0.019592 | 0.116300 | 0.072656 | -0.021633 |
# Step 2: Calculate daily log returns from cumulative log returns
daily_log_returns_kalman = combined_df_kalman_cleaned.diff().fillna(0)
# Initialize a DataFrame to hold the adjusted weights
adjusted_weights = pd.DataFrame(index=daily_log_returns_kalman.index, columns=daily_log_returns_kalman.columns)
# Calculate weights dynamically each day using cumulative returns to check asset activity
for date, returns in combined_df_kalman_cleaned.iterrows():
# Use the cumulative returns to determine active assets
active_assets = returns[returns != 0].count() # Count non-zero cumulative returns for the day
if active_assets > 0:
daily_weights = 1 / active_assets # Equal weight divided by the number of active assets
else:
daily_weights = 0 # No active assets to invest in
adjusted_weights.loc[date] = daily_weights
# Save the adjusted weights to an Excel file
adjusted_weights.to_excel('rebalanced_weights_equalweighted_kalman.xlsx')
# Step 3: Calculate portfolio returns using the dynamically adjusted weights
portfolio_kalman_log_returns = (daily_log_returns_kalman * adjusted_weights).sum(axis=1)
portfolio_kalman_simple_returns = np.exp(portfolio_kalman_log_returns) - 1
portfolio_kalman_cumulative_simple_returns = (1 + portfolio_kalman_simple_returns).cumprod() - 1
# Step 4: Plot the performance
trace = go.Scatter(x=combined_df_kalman_cleaned.index, y=portfolio_kalman_cumulative_simple_returns, mode='lines', name='Cumulative Simple Returns')
layout = go.Layout(title='Equal-weighted Portfolio Kalman - Adjusted Over Time', xaxis=dict(title='Days'), yaxis=dict(title='Simple Return'))
fig = go.Figure(data=[trace], layout=layout)
fig.show()
<ipython-input-66-88a7dd3d8b5e>:18: UserWarning: Pandas requires version '1.4.3' or newer of 'xlsxwriter' (version '1.3.8' currently installed).
window = 20
#strategy_start = '2000-01-01'
window_history = window + 10 # Define the window size as 15 days + 10 to have enough history
start_date = pd.to_datetime(strategy_start) # Convert start_date to datetime object
adjusted_start_date = start_date - pd.DateOffset(days=window_history) # Calculate adjusted start date
# Dictionary to store the filtered DataFrames
filtered_dfs = {}
# Loop through each header in new_headers
for header in new_headers:
# Access the DataFrame for the current header
df = strategy_SMA[header]
# Check if the DataFrame has an index that includes the range we need
if df.index.min() <= adjusted_start_date and df.index.max() >= start_date:
# Filter the DataFrame to show data from adjusted_start_date to start_date
filtered_df = df.loc[adjusted_start_date:start_date]
# Store the filtered DataFrame in the dictionary
filtered_dfs[header] = filtered_df
#initial_investment = 1000000
#strategy_start = '2000-01-01'
for header in new_headers:
# Running total of log returns based on trade signals
running_total = float(0)
for date, row in filtered_dfs[header].iterrows():
# Update running total based on trade signals
if row['Signal_SMA_shifted'] == 1: # Buy signal
running_total += row['Log_Return']
elif row['Signal_SMA_shifted'] == -1: # Sell signal
running_total -= row['Log_Return']
# Calculate cumulative returns
cumulative_log_return = np.exp(running_total) - 1
# Store the running total and the cumulative returns in the DataFrame
filtered_dfs[header].loc[date, 'Cumulative_Log_Returns'] = running_total
filtered_dfs[header].loc[date, 'Total_Log_Return'] = initial_investment * (1 + cumulative_log_return)
<ipython-input-69-d562b774e648>:19: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy <ipython-input-69-d562b774e648>:20: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
# Assuming new_headers and filtered_dfs are already defined and populated
# List to hold the data series for total log returns
data_series_list_total_log_return = []
# Extract 'Total_Log_Return' from each filtered DataFrame and rename it uniquely
for header in new_headers:
if 'Cumulative_Log_Returns' in filtered_dfs[header].columns:
# Extract the series and rename it with its asset name
series = filtered_dfs[header]['Cumulative_Log_Returns'].rename(header)
data_series_list_total_log_return.append(series)
# Combine all the series into a single DataFrame
combined_df_total_log_return = pd.concat(data_series_list_total_log_return, axis=1, join='outer')
# Forward fill missing values, if necessary
combined_df_filled_total_log_return = combined_df_total_log_return.ffill()
# Drop rows where any NaN values still exist (likely at the start)
combined_df_cleaned_total_log_return = combined_df_filled_total_log_return.dropna()
# Concatenate the two DataFrames
combined_df_SMA_cleaned_vol = pd.concat([combined_df_cleaned_total_log_return, combined_df_SMA_cleaned])
# Check the concatenated result
combined_df_SMA_cleaned_vol.head(20)
| USD Future | EUR Future (USD) | JPY Future (USD) | GBP Future (USD) | GBP Future (EUR) | CAD Future (USD) | CHF Future (USD) | S&P 500 | Nasdaq 100 | S&P Canada 60 | FTSE 100 | DAX | SMI | CAC - 40 | IBEX 35 | Euro Stoxx 50 | Nikkei 225 | Hang Seng Index | US 2-year | US 5-year | US 10-year | Long Gilt (10 year) | Euro-Schatz-Futures (2 year) | Euro-Bobl-Future (5 year) | Euro-Bund-Future (10 year) | Euro-Buxl-Future (30 year) | Brent Crude Oil | WTI Crude Oil | Heating Oil | Natural Gas | Gold | Silver | Platinum | Palladium | Copper | Nickel | Zinc | Lean hogs | Live cattle | Feeder cattle | Wheat | Corn | Oat | Soybeans | Soybean oil | Frozen orange juice | Cocoa | Coffee | Sugar No.11 | Cotton No.2 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Date | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 1999-12-02 | 0.004590 | 0.006265 | 0.000000 | 4.709523e-04 | 0.0 | -0.004508 | 0.004931 | 0.006932 | 0.0 | 0.0 | 0.001339 | 0.000488 | -0.001752 | -0.005761 | 0.009062 | -0.001177 | -0.008317 | 0.007219 | 0.000413 | 9.188010e-04 | 0.001871 | 0.005999 | 0.001356 | 0.002393 | 0.008732 | 0.008788 | 0.038264 | 0.032342 | 0.032365 | -0.028020 | -0.016580 | 0.016017 | -0.005473 | 0.012976 | -0.008719 | 0.011721 | -0.012531 | 0.001436 | -0.004316 | -0.000593 | 0.017043 | 0.001234 | -6.706804e-03 | 0.006853 | 0.016702 | 0.009761 | 2.330022e-02 | 3.823561e-02 | 0.001726 | 0.003552 |
| 1999-12-03 | 0.004692 | 0.006566 | -0.000616 | 1.544988e-17 | 0.0 | -0.006013 | 0.002384 | 0.024825 | 0.0 | 0.0 | 0.014686 | 0.025189 | 0.006006 | 0.011870 | 0.022211 | 0.018092 | -0.006757 | 0.026087 | -0.001191 | -2.865824e-03 | -0.002934 | 0.009766 | 0.000290 | -0.000287 | 0.005635 | 0.001889 | 0.037795 | 0.031929 | 0.028755 | 0.026250 | -0.034136 | 0.014052 | -0.008097 | 0.018845 | 0.008030 | 0.043510 | 0.006418 | 0.008575 | -0.005046 | 0.004728 | 0.035411 | 0.006184 | -8.930772e-03 | 0.007379 | 0.026386 | 0.013333 | 3.754547e-02 | 9.610882e-02 | -0.037425 | 0.017286 |
| 1999-12-06 | -0.009850 | -0.013086 | -0.004212 | -1.130333e-02 | 0.0 | -0.003010 | -0.014956 | 0.016267 | 0.0 | 0.0 | 0.022056 | 0.049985 | 0.008898 | 0.041281 | 0.022211 | 0.052100 | -0.008525 | 0.044097 | -0.001511 | -3.323595e-03 | -0.004530 | -0.006353 | -0.000584 | -0.002783 | -0.021539 | -0.010580 | 0.071039 | 0.064272 | 0.047223 | 0.073240 | -0.020204 | 0.012092 | -0.010256 | 0.039639 | 0.010483 | 0.051454 | 0.019138 | 0.003828 | -0.006482 | 0.000296 | 0.015023 | -0.008595 | -2.217666e-02 | -0.001050 | 0.033687 | 0.008739 | 2.330022e-02 | 2.788417e-02 | 0.003538 | 0.020496 |
| 1999-12-07 | -0.012128 | -0.015335 | 0.002352 | -7.983498e-03 | 0.0 | -0.003010 | -0.016355 | 0.009406 | 0.0 | 0.0 | 0.017793 | 0.050992 | 0.004148 | 0.045323 | 0.059892 | 0.050696 | 0.003030 | 0.040656 | -0.002015 | -5.266786e-03 | -0.007716 | -0.015174 | -0.000195 | -0.003166 | -0.022935 | -0.014139 | 0.055478 | 0.047722 | 0.024201 | 0.052328 | -0.045753 | 0.004799 | -0.009064 | 0.033908 | -0.004972 | 0.012733 | 0.003426 | -0.003355 | -0.004685 | 0.003548 | 0.023128 | -0.002463 | -1.777751e-02 | -0.008886 | 0.023344 | 0.002066 | -6.885499e-03 | 2.079859e-02 | -0.022492 | 0.005927 |
| 1999-12-08 | -0.013716 | -0.017961 | -0.003079 | -5.864573e-03 | 0.0 | -0.006013 | -0.018387 | 0.002141 | 0.0 | 0.0 | 0.013134 | 0.050758 | 0.000955 | 0.045421 | 0.059892 | 0.057004 | -0.015532 | 0.030574 | -0.001420 | -3.781156e-03 | -0.006390 | -0.015793 | 0.000388 | -0.001727 | -0.025188 | -0.011259 | 0.066943 | 0.059657 | 0.036606 | 0.044869 | -0.050322 | 0.010135 | -0.008816 | 0.036842 | -0.008719 | 0.018412 | -0.001718 | -0.006233 | 0.003567 | 0.011185 | 0.039539 | 0.013656 | -6.706804e-03 | 0.008438 | 0.033093 | -0.009334 | 6.071532e-18 | -1.346433e-02 | -0.029058 | 0.013685 |
| 1999-12-09 | -0.010343 | -0.011718 | 0.001225 | -7.983498e-03 | 0.0 | -0.009016 | -0.012299 | 0.005686 | 0.0 | 0.0 | 0.020884 | 0.044052 | -0.003758 | 0.048473 | 0.058859 | 0.056264 | -0.020567 | 0.060987 | -0.001877 | -4.809904e-03 | -0.007981 | -0.019453 | -0.000584 | -0.004411 | -0.022890 | -0.013631 | 0.042011 | 0.044869 | 0.013493 | 0.046182 | -0.063786 | 0.012504 | -0.016261 | 0.034150 | -0.003099 | 0.024182 | 0.004712 | -0.017375 | -0.002164 | 0.007958 | 0.043684 | 0.027502 | -4.477880e-03 | 0.035280 | 0.064762 | -0.001551 | -2.051588e-02 | -6.798358e-02 | -0.017500 | 0.017286 |
| 1999-12-10 | -0.003536 | -0.002568 | 0.001944 | -1.043912e-02 | 0.0 | -0.010516 | -0.002857 | 0.010113 | 0.0 | 0.0 | 0.027664 | 0.033574 | -0.019819 | 0.028262 | 0.038236 | 0.033632 | -0.017422 | 0.059040 | -0.002746 | -7.320175e-03 | -0.012739 | -0.024332 | -0.001554 | -0.006992 | -0.021551 | -0.021218 | 0.017879 | 0.009136 | -0.015226 | -0.021906 | -0.066279 | 0.010135 | -0.005226 | 0.057995 | -0.013099 | 0.015262 | -0.003657 | -0.026665 | -0.015911 | -0.002075 | 0.039539 | 0.022445 | -4.477880e-03 | 0.032021 | 0.066023 | -0.021395 | -8.256928e-03 | -2.986440e-02 | -0.029058 | 0.016283 |
| 1999-12-13 | -0.004234 | -0.004428 | -0.006763 | -8.381297e-03 | 0.0 | -0.012019 | -0.004106 | 0.010287 | 0.0 | 0.0 | 0.024431 | 0.035195 | -0.017834 | 0.035801 | 0.042070 | 0.037825 | -0.032808 | 0.055331 | -0.002106 | -6.179924e-03 | -0.011155 | -0.023580 | -0.000778 | -0.004698 | -0.014199 | -0.015322 | 0.022657 | 0.015041 | 0.007606 | -0.047337 | -0.070201 | 0.010546 | 0.007788 | 0.074471 | -0.006217 | 0.010476 | -0.000893 | -0.033914 | -0.019564 | -0.003263 | 0.056223 | 0.035135 | 9.006133e-03 | 0.053949 | 0.080686 | -0.037343 | 3.277447e-02 | -5.095131e-02 | -0.030706 | 0.015082 |
| 1999-12-14 | 0.002560 | 0.004031 | -0.010122 | -1.610334e-02 | 0.0 | -0.010514 | 0.003735 | 0.002426 | 0.0 | 0.0 | 0.016421 | 0.043739 | -0.013049 | 0.036612 | 0.038449 | 0.039288 | -0.036059 | 0.046346 | 0.000138 | -1.605873e-03 | -0.003200 | -0.011770 | 0.000290 | -0.002591 | -0.003716 | -0.003254 | 0.047605 | 0.028823 | 0.028136 | -0.077178 | -0.069833 | -0.002340 | 0.005908 | 0.087685 | 0.002481 | 0.014131 | 0.007152 | -0.014557 | -0.016275 | -0.003263 | 0.041609 | 0.018669 | 4.336809e-17 | 0.049525 | 0.074272 | -0.052461 | 2.897399e-02 | -6.594041e-02 | -0.054272 | 0.012686 |
| 1999-12-15 | 0.002756 | 0.002649 | -0.012164 | -1.161588e-02 | 0.0 | -0.009007 | 0.002164 | 0.004879 | 0.0 | 0.0 | 0.002936 | 0.044478 | -0.008180 | 0.026054 | 0.027260 | 0.032383 | -0.040092 | 0.017607 | 0.000917 | -3.816392e-17 | -0.000267 | -0.010441 | -0.000486 | -0.004890 | -0.007365 | -0.010071 | 0.066031 | 0.052999 | 0.048254 | -0.038127 | -0.079018 | -0.001425 | -0.012171 | 0.087914 | 0.040108 | 0.036152 | 0.016383 | -0.006121 | -0.018101 | -0.002966 | 0.041609 | 0.018669 | 1.581952e-02 | 0.050079 | 0.074272 | -0.070027 | 1.718974e-02 | -1.929078e-02 | -0.030138 | 0.021100 |
| 1999-12-16 | -0.004234 | -0.006779 | -0.006456 | -1.510043e-02 | 0.0 | -0.013521 | -0.005509 | 0.010808 | 0.0 | 0.0 | 0.010410 | 0.071117 | -0.021820 | 0.037582 | 0.040593 | 0.047345 | -0.033427 | 0.010303 | 0.002110 | 2.183532e-03 | 0.004551 | 0.000842 | 0.003014 | 0.002987 | -0.001683 | 0.011561 | 0.089933 | 0.070656 | 0.069578 | -0.096715 | -0.081826 | -0.006194 | -0.007626 | 0.107454 | 0.041296 | 0.044365 | 0.034597 | -0.013213 | -0.016275 | -0.003263 | 0.031300 | 0.013656 | 3.189332e-02 | 0.053397 | 0.085194 | -0.049204 | 9.255041e-03 | -4.406198e-16 | -0.031968 | 0.037936 |
| 1999-12-17 | 0.001876 | 0.001760 | -0.007777 | -1.134733e-02 | 0.0 | -0.015024 | 0.004049 | 0.015666 | 0.0 | 0.0 | 0.017015 | 0.073383 | -0.020706 | 0.033335 | 0.049056 | 0.052026 | -0.033061 | 0.030583 | 0.002294 | 2.643832e-03 | 0.004819 | 0.003679 | 0.002819 | 0.003855 | 0.008547 | 0.016955 | 0.092603 | 0.067270 | 0.074640 | -0.103897 | -0.075872 | -0.008418 | -0.022779 | 0.116741 | 0.046635 | 0.041920 | 0.025529 | -0.015893 | -0.015911 | -0.005643 | 0.021096 | 0.006184 | 2.727066e-02 | 0.051184 | 0.087769 | -0.064504 | 3.134760e-02 | 1.177610e-02 | -0.054272 | 0.032427 |
| 1999-12-20 | -0.001569 | -0.001682 | -0.000885 | -1.195146e-02 | 0.0 | -0.015024 | -0.001909 | 0.009245 | 0.0 | 0.0 | 0.017581 | 0.072012 | -0.024185 | 0.029676 | 0.055017 | 0.058351 | -0.028240 | 0.046758 | 0.002892 | 4.833151e-03 | 0.008853 | 0.004440 | 0.002527 | 0.004241 | 0.010384 | 0.019926 | 0.084122 | 0.060461 | 0.079558 | -0.094056 | -0.074112 | -0.003254 | -0.024012 | 0.111317 | 0.048405 | 0.034552 | 0.018888 | -0.022164 | -0.013361 | -0.005941 | 0.009990 | -0.002463 | 2.727066e-02 | 0.037458 | 0.074926 | -0.051374 | 4.957352e-02 | 3.344288e-02 | -0.067791 | 0.034058 |
| 1999-12-21 | -0.000977 | 0.001270 | 0.001542 | -1.610334e-02 | 0.0 | -0.016527 | 0.001223 | 0.022738 | 0.0 | 0.0 | 0.019897 | 0.080497 | -0.015171 | 0.033642 | 0.046367 | 0.049064 | -0.019231 | 0.043853 | 0.003121 | 5.525512e-03 | 0.010471 | -0.000081 | 0.001554 | 0.001541 | 0.003443 | 0.009307 | 0.083674 | 0.057443 | 0.075230 | -0.052505 | -0.064033 | 0.003367 | -0.009064 | 0.107799 | 0.032332 | 0.027998 | 0.015964 | -0.016788 | -0.008290 | 0.001776 | 0.022111 | 0.002469 | 2.267445e-02 | 0.041284 | 0.076819 | -0.057917 | 4.957352e-02 | -8.074367e-02 | -0.074479 | 0.026747 |
| 1999-12-22 | -0.001174 | 0.001071 | 0.005463 | -1.349369e-02 | 0.0 | -0.018029 | 0.002007 | 0.024800 | 0.0 | 0.0 | 0.016285 | 0.088800 | -0.014538 | 0.051278 | 0.047984 | 0.069496 | 0.002108 | 0.042255 | 0.003305 | 5.871872e-03 | 0.011011 | 0.010945 | 0.002333 | 0.002601 | 0.007902 | 0.011387 | 0.057781 | 0.027993 | 0.058148 | -0.021088 | -0.064714 | -0.009428 | 0.015056 | 0.112228 | 0.056642 | 0.054202 | 0.033776 | -0.021264 | -0.008652 | 0.002071 | 0.014014 | -0.003693 | 2.267445e-02 | 0.019091 | 0.052209 | -0.066159 | 7.011214e-02 | -1.063375e-01 | -0.069335 | 0.028771 |
| 1999-12-23 | -0.006603 | -0.004527 | 0.004261 | -1.757246e-02 | 0.0 | -0.024026 | -0.001284 | 0.040459 | 0.0 | 0.0 | 0.028903 | 0.141231 | -0.032359 | 0.076650 | 0.065232 | 0.097409 | 0.002108 | 0.049631 | 0.003397 | 6.564953e-03 | 0.012092 | 0.004863 | 0.002138 | 0.002023 | 0.000030 | 0.008615 | 0.079630 | 0.042417 | 0.066070 | -0.002505 | -0.065415 | -0.005586 | 0.006372 | 0.118212 | 0.055472 | 0.053961 | 0.035828 | -0.019023 | -0.004325 | 0.007664 | 0.006983 | -0.007371 | 2.038425e-02 | 0.019091 | 0.049121 | -0.065052 | 2.094561e-02 | -7.619713e-02 | -0.067647 | 0.020496 |
| 1999-12-24 | -0.004328 | -0.004527 | 0.004261 | -1.757246e-02 | 0.0 | -0.024026 | -0.001284 | 0.040459 | 0.0 | 0.0 | 0.033588 | 0.141231 | -0.032359 | 0.091136 | 0.065232 | 0.097409 | -0.001501 | 0.083227 | 0.003397 | 6.564953e-03 | 0.012092 | 0.004477 | 0.002138 | 0.002023 | 0.000030 | 0.008615 | 0.080530 | 0.042417 | 0.066070 | -0.002505 | -0.065415 | -0.005586 | 0.006372 | 0.118212 | 0.055472 | 0.069435 | 0.026564 | -0.019023 | -0.004325 | 0.007664 | 0.006983 | -0.007371 | 2.038425e-02 | 0.019091 | 0.049121 | -0.065052 | 2.094561e-02 | -7.619713e-02 | -0.067647 | 0.020496 |
| 1999-12-27 | -0.004724 | -0.002469 | -0.001490 | -1.557259e-02 | 0.0 | -0.016580 | 0.001693 | 0.038599 | 0.0 | 0.0 | 0.033588 | 0.149890 | -0.030447 | 0.086506 | 0.059885 | 0.103571 | 0.002690 | 0.083227 | 0.002846 | 5.871872e-03 | 0.011281 | 0.004477 | 0.001360 | 0.001252 | -0.000144 | 0.007404 | 0.080530 | 0.060059 | 0.084014 | 0.040127 | -0.060916 | -0.007104 | 0.001646 | 0.129295 | 0.054300 | 0.069530 | 0.026854 | -0.019023 | -0.005046 | 0.004433 | 0.018055 | -0.006146 | 2.038425e-02 | 0.037458 | 0.066670 | -0.079480 | 1.251465e-02 | -6.880187e-02 | -0.074479 | 0.038347 |
| 1999-12-28 | -0.001174 | 0.004323 | -0.002198 | -1.697208e-02 | 0.0 | -0.009189 | 0.009264 | 0.039273 | 0.0 | 0.0 | 0.033588 | 0.139680 | -0.028994 | 0.079541 | 0.042981 | 0.092428 | 0.012125 | 0.090569 | 0.003305 | 7.142888e-03 | 0.013445 | 0.004477 | 0.002333 | 0.003951 | 0.011873 | 0.013646 | 0.080530 | 0.078580 | 0.098821 | 0.008828 | -0.055066 | -0.004674 | 0.015298 | 0.129750 | 0.054886 | 0.069530 | 0.026854 | -0.041207 | -0.005046 | 0.004728 | 0.017043 | -0.009816 | 2.267445e-02 | 0.038006 | 0.071012 | -0.076694 | 3.515712e-02 | -9.492794e-02 | -0.074479 | 0.037119 |
| 1999-12-29 | -0.000873 | 0.005414 | -0.000378 | -1.510653e-02 | 0.0 | -0.013617 | 0.010529 | 0.041637 | 0.0 | 0.0 | 0.039158 | 0.141753 | -0.033266 | 0.079758 | 0.048237 | 0.100643 | 0.012289 | 0.071236 | 0.002662 | 6.102846e-03 | 0.011822 | 0.002788 | 0.002138 | 0.004048 | 0.013437 | 0.013820 | 0.089933 | 0.065472 | 0.093272 | -0.001670 | -0.051977 | -0.037091 | 0.022512 | 0.141910 | 0.062481 | 0.065499 | 0.046017 | -0.050871 | -0.004325 | 0.006488 | 0.019067 | -0.004920 | 2.038425e-02 | 0.045533 | 0.080375 | -0.067811 | 2.566038e-02 | -8.655975e-02 | -0.110910 | 0.023112 |
window
20
# Function to calculate rebalanced weights based on 12-day volatility
def calculate_rebalanced_weights_volatility(df, window):
# Calculate rolling standard deviation for each asset
rolling_vol = df.diff().rolling(window=window).std().fillna(0)
small_constant = 1e-8 # Small constant to avoid division by zero
# Calculate inverse volatility, avoiding division by zero by adding small constant
# Only consider non-zero volatilities in the weight calculation
inverse_volatility = 1 / (rolling_vol + small_constant)
inverse_volatility[rolling_vol == 0] = 0 # Set inverse volatility to zero where rolling volatility is zero
# Sum of inverse volatilities (excluding those set to zero)
sum_inverse_volatility = inverse_volatility.sum(axis=1)
# Initialize daily weights DataFrame
daily_weights = pd.DataFrame(index=df.index, columns=df.columns)
# Assign weights daily based on non-zero inverse volatility
for day in range(len(daily_weights)):
daily_weights.iloc[day] = inverse_volatility.iloc[day] / sum_inverse_volatility.iloc[day]
return daily_weights
# Ensure the DataFrame index is in datetime format
combined_df_SMA_cleaned_vol.index = pd.to_datetime(combined_df_SMA_cleaned_vol.index)
# Calculate daily rebalanced weights based on volatility using the full dataset
weights_SMA_vol = calculate_rebalanced_weights_volatility(combined_df_SMA_cleaned_vol, window)
# Starting calculation from the start date
#start_date = '2000-01-01'
# Filter the weights and returns dataframes from the start date
weights_SMA_vol_from_start = weights_SMA_vol[weights_SMA_vol.index >= start_date]
daily_log_returns_SMA_vol = combined_df_SMA_cleaned_vol.diff().fillna(0)[combined_df_SMA_cleaned_vol.index >= start_date]
# Calculate portfolio log returns using the new weights
portfolio_SMA_log_returns_vol = (daily_log_returns_SMA_vol * weights_SMA_vol_from_start).sum(axis=1)
portfolio_SMA_simple_returns_vol = np.exp(portfolio_SMA_log_returns_vol) - 1
portfolio_SMA_cumulative_simple_returns_vol = (1 + portfolio_SMA_simple_returns_vol).cumprod() - 1
# Plot the performance
trace = go.Scatter(x=weights_SMA_vol_from_start.index, y=portfolio_SMA_cumulative_simple_returns_vol, mode='lines', name='Cumulative Simple Returns with Daily Rebalancing')
data = [trace]
layout = go.Layout(title='Inverse Volatility Weighted Portfolio SMA with Daily Rebalancing - from 2000', xaxis=dict(title='Days'), yaxis=dict(title='Simple Return'))
fig = go.Figure(data=data, layout=layout)
fig.show()
# Save the weights to an Excel file
weights_SMA_vol_from_start.to_excel('rebalanced_weights_volatility_SMA.xlsx')
<ipython-input-72-0f0ec232555d>:48: UserWarning: Pandas requires version '1.4.3' or newer of 'xlsxwriter' (version '1.3.8' currently installed).
#strategy_start = '2000-01-01'
window_history = window + 10 # Define the window size as 15 days + 10 to have enough history
start_date = pd.to_datetime(strategy_start) # Convert start_date to datetime object
adjusted_start_date = start_date - pd.DateOffset(days=window_history) # Calculate adjusted start date
# Dictionary to store the filtered DataFrames
filtered_dfs = {}
# Loop through each header in new_headers
for header in new_headers:
# Access the DataFrame for the current header
df = strategy_SMA_bands[header]
# Check if the DataFrame has an index that includes the range we need
if df.index.min() <= adjusted_start_date and df.index.max() >= start_date:
# Filter the DataFrame to show data from adjusted_start_date to start_date
filtered_df = df.loc[adjusted_start_date:start_date]
# Store the filtered DataFrame in the dictionary
filtered_dfs[header] = filtered_df
#initial_investment = 1000000
#strategy_start = '2000-01-01'
for header in new_headers:
# Running total of log returns based on trade signals
running_total = float(0)
for date, row in filtered_dfs[header].iterrows():
# Update running total based on trade signals
if row['Signal_SMA_with_Band_shifted'] == 1: # Buy signal
running_total += row['Log_Return']
elif row['Signal_SMA_with_Band_shifted'] == -1: # Sell signal
running_total -= row['Log_Return']
# Calculate cumulative returns
cumulative_log_return = np.exp(running_total) - 1
# Store the running total and the cumulative returns in the DataFrame
filtered_dfs[header].loc[date, 'Cumulative_Log_Returns'] = running_total
filtered_dfs[header].loc[date, 'Total_Log_Return'] = initial_investment * (1 + cumulative_log_return)
<ipython-input-74-b374e6ce1920>:19: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy <ipython-input-74-b374e6ce1920>:20: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
# Assuming new_headers and filtered_dfs are already defined and populated
# List to hold the data series for total log returns
data_series_list_total_log_return = []
# Extract 'Total_Log_Return' from each filtered DataFrame and rename it uniquely
for header in new_headers:
if 'Cumulative_Log_Returns' in filtered_dfs[header].columns:
# Extract the series and rename it with its asset name
series = filtered_dfs[header]['Cumulative_Log_Returns'].rename(header)
data_series_list_total_log_return.append(series)
# Combine all the series into a single DataFrame
combined_df_total_log_return = pd.concat(data_series_list_total_log_return, axis=1, join='outer')
# Forward fill missing values, if necessary
combined_df_filled_total_log_return = combined_df_total_log_return.ffill()
# Drop rows where any NaN values still exist (likely at the start)
combined_df_cleaned_total_log_return = combined_df_filled_total_log_return.dropna()
# Concatenate the two DataFrames
combined_df_SMA_bands_cleaned_vol = pd.concat([combined_df_cleaned_total_log_return, combined_df_SMA_bands_cleaned])
# Check the concatenated result
combined_df_SMA_bands_cleaned_vol.head(20)
| USD Future | EUR Future (USD) | JPY Future (USD) | GBP Future (USD) | GBP Future (EUR) | CAD Future (USD) | CHF Future (USD) | S&P 500 | Nasdaq 100 | S&P Canada 60 | FTSE 100 | DAX | SMI | CAC - 40 | IBEX 35 | Euro Stoxx 50 | Nikkei 225 | Hang Seng Index | US 2-year | US 5-year | US 10-year | Long Gilt (10 year) | Euro-Schatz-Futures (2 year) | Euro-Bobl-Future (5 year) | Euro-Bund-Future (10 year) | Euro-Buxl-Future (30 year) | Brent Crude Oil | WTI Crude Oil | Heating Oil | Natural Gas | Gold | Silver | Platinum | Palladium | Copper | Nickel | Zinc | Lean hogs | Live cattle | Feeder cattle | Wheat | Corn | Oat | Soybeans | Soybean oil | Frozen orange juice | Cocoa | Coffee | Sugar No.11 | Cotton No.2 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Date | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 1999-12-02 | 0.004590 | 0.006265 | 0.000000 | 0.0 | 0.0 | 0.000000 | 0.004931 | 0.006932 | 0.0 | 0.0 | 0.001339 | 0.000488 | 0.000000 | -0.005761 | 0.009062 | -0.001177 | -0.008317 | 0.007219 | 0.000000 | 0.000919 | 0.001871 | 0.005999 | 0.0 | 0.002393 | 0.008732 | 0.008788 | 0.038264 | 0.032342 | 0.032365 | -0.028020 | -0.016580 | 0.016017 | -0.005473 | 0.012976 | -0.008719 | 0.011721 | -0.012531 | 0.001436 | -0.004316 | -0.000593 | 0.017043 | 0.001234 | -6.706804e-03 | 0.006853 | 0.016702 | 0.009761 | 2.330022e-02 | 3.823561e-02 | 0.001726 | 0.003552 |
| 1999-12-03 | 0.004692 | 0.006566 | -0.000616 | 0.0 | 0.0 | 0.000000 | 0.002384 | 0.024825 | 0.0 | 0.0 | 0.014686 | 0.025189 | 0.000000 | 0.011870 | 0.022211 | 0.018092 | -0.006757 | 0.026087 | 0.000000 | -0.002866 | -0.002934 | 0.009766 | 0.0 | -0.000287 | 0.005635 | 0.001889 | 0.037795 | 0.031929 | 0.028755 | 0.026250 | -0.034136 | 0.014052 | -0.008097 | 0.018845 | 0.008030 | 0.043510 | 0.006418 | 0.008575 | -0.005046 | 0.004728 | 0.035411 | 0.006184 | -8.930772e-03 | 0.007379 | 0.026386 | 0.013333 | 3.754547e-02 | 9.610882e-02 | -0.037425 | 0.017286 |
| 1999-12-06 | -0.009850 | -0.013086 | -0.004212 | 0.0 | 0.0 | 0.000000 | -0.014956 | 0.016267 | 0.0 | 0.0 | 0.022056 | 0.049985 | 0.000000 | 0.041281 | 0.022211 | 0.052100 | -0.008525 | 0.044097 | 0.000000 | -0.003324 | -0.004530 | -0.006353 | 0.0 | -0.002783 | -0.021539 | -0.010580 | 0.071039 | 0.064272 | 0.047223 | 0.073240 | -0.034136 | 0.012092 | -0.010256 | 0.039639 | 0.010483 | 0.051454 | 0.019138 | 0.003828 | -0.006482 | 0.000296 | 0.015023 | -0.008595 | -2.217666e-02 | -0.001050 | 0.033687 | 0.008739 | 2.330022e-02 | 2.788417e-02 | -0.037425 | 0.020496 |
| 1999-12-07 | -0.012128 | -0.015335 | 0.002352 | 0.0 | 0.0 | 0.000000 | -0.016355 | 0.009406 | 0.0 | 0.0 | 0.017793 | 0.050992 | -0.004750 | 0.045323 | 0.059892 | 0.050696 | 0.003030 | 0.040656 | 0.000000 | -0.005267 | -0.007716 | -0.015174 | 0.0 | -0.003166 | -0.022935 | -0.014139 | 0.055478 | 0.047722 | 0.024201 | 0.052328 | -0.059686 | 0.004799 | -0.009064 | 0.033908 | -0.004972 | 0.012733 | 0.003426 | -0.003355 | -0.004685 | 0.003548 | 0.023128 | -0.002463 | -1.777751e-02 | -0.008886 | 0.023344 | 0.002066 | -6.885499e-03 | 2.079859e-02 | -0.063455 | 0.005927 |
| 1999-12-08 | -0.012128 | -0.017961 | -0.003079 | 0.0 | 0.0 | 0.000000 | -0.018387 | 0.002141 | 0.0 | 0.0 | 0.013134 | 0.050758 | -0.004750 | 0.045421 | 0.059892 | 0.057004 | -0.015532 | 0.030574 | 0.000000 | -0.005267 | -0.006390 | -0.015793 | 0.0 | -0.001727 | -0.025188 | -0.011259 | 0.066943 | 0.059657 | 0.036606 | 0.044869 | -0.059686 | 0.010135 | -0.008816 | 0.036842 | -0.008719 | 0.018412 | -0.001718 | -0.006233 | 0.003567 | 0.011185 | 0.039539 | 0.013656 | -6.706804e-03 | 0.008438 | 0.033093 | -0.009334 | 6.071532e-18 | -1.346433e-02 | -0.070021 | 0.013685 |
| 1999-12-09 | -0.012128 | -0.011718 | 0.001225 | 0.0 | 0.0 | 0.000000 | -0.012299 | 0.005686 | 0.0 | 0.0 | 0.020884 | 0.044052 | -0.004750 | 0.048473 | 0.058859 | 0.056264 | -0.020567 | 0.060987 | 0.000000 | -0.006296 | -0.007981 | -0.019453 | 0.0 | -0.004411 | -0.022890 | -0.013631 | 0.042011 | 0.044869 | 0.013493 | 0.046182 | -0.059686 | 0.012504 | -0.016261 | 0.034150 | -0.003099 | 0.024182 | 0.004712 | -0.017375 | -0.002164 | 0.007958 | 0.043684 | 0.027502 | -4.477880e-03 | 0.035280 | 0.064762 | -0.001551 | -2.051588e-02 | -6.798358e-02 | -0.058462 | 0.017286 |
| 1999-12-10 | -0.012128 | -0.002568 | 0.001944 | 0.0 | 0.0 | 0.000000 | -0.002857 | 0.010113 | 0.0 | 0.0 | 0.027664 | 0.033574 | -0.004750 | 0.028262 | 0.038236 | 0.033632 | -0.017422 | 0.059040 | 0.000000 | -0.006296 | -0.007981 | -0.019453 | 0.0 | -0.004411 | -0.021551 | -0.021218 | 0.017879 | 0.009136 | -0.015226 | -0.021906 | -0.059686 | 0.010135 | -0.005226 | 0.057995 | -0.013099 | 0.015262 | -0.003657 | -0.026665 | -0.015911 | -0.002075 | 0.039539 | 0.022445 | -4.477880e-03 | 0.032021 | 0.066023 | -0.021395 | -8.256928e-03 | -2.986440e-02 | -0.070021 | 0.016283 |
| 1999-12-13 | -0.012825 | -0.004428 | -0.006763 | 0.0 | 0.0 | 0.000000 | -0.004106 | 0.010287 | 0.0 | 0.0 | 0.024431 | 0.035195 | -0.002765 | 0.035801 | 0.042070 | 0.037825 | -0.032808 | 0.055331 | 0.000000 | -0.006296 | -0.007981 | -0.019453 | 0.0 | -0.004411 | -0.014199 | -0.015322 | 0.022657 | 0.015041 | 0.007606 | -0.047337 | -0.059686 | 0.010546 | 0.007788 | 0.074471 | -0.006217 | 0.010476 | -0.000893 | -0.033914 | -0.019564 | -0.003263 | 0.056223 | 0.035135 | 9.006133e-03 | 0.053949 | 0.080686 | -0.037343 | 3.277447e-02 | -5.095131e-02 | -0.071669 | 0.015082 |
| 1999-12-14 | -0.006032 | 0.004031 | -0.010122 | 0.0 | 0.0 | 0.000000 | 0.003735 | 0.002426 | 0.0 | 0.0 | 0.016421 | 0.043739 | 0.002020 | 0.036612 | 0.038449 | 0.039288 | -0.036059 | 0.046346 | 0.000000 | -0.006296 | -0.007981 | -0.019453 | 0.0 | -0.004411 | -0.003716 | -0.003254 | 0.047605 | 0.028823 | 0.028136 | -0.077178 | -0.059686 | -0.002340 | 0.005908 | 0.087685 | 0.002481 | 0.014131 | 0.007152 | -0.014557 | -0.016275 | -0.003263 | 0.041609 | 0.018669 | 4.336809e-17 | 0.049525 | 0.074272 | -0.052461 | 2.897399e-02 | -6.594041e-02 | -0.095234 | 0.012686 |
| 1999-12-15 | -0.005835 | 0.002649 | -0.012164 | 0.0 | 0.0 | 0.000000 | 0.002164 | 0.004879 | 0.0 | 0.0 | 0.002936 | 0.044478 | 0.006889 | 0.026054 | 0.027260 | 0.032383 | -0.040092 | 0.017607 | 0.000000 | -0.004690 | -0.005048 | -0.018125 | 0.0 | -0.006710 | -0.007365 | -0.010071 | 0.066031 | 0.052999 | 0.048254 | -0.038127 | -0.059686 | -0.002340 | -0.012171 | 0.087914 | 0.040108 | 0.036152 | 0.016383 | -0.006121 | -0.018101 | -0.002966 | 0.041609 | 0.018669 | 1.581952e-02 | 0.050079 | 0.074272 | -0.070027 | 1.718974e-02 | -1.929078e-02 | -0.071100 | 0.021100 |
| 1999-12-16 | -0.012825 | -0.006779 | -0.006456 | 0.0 | 0.0 | 0.000000 | -0.005509 | 0.010808 | 0.0 | 0.0 | 0.010410 | 0.071117 | -0.006751 | 0.037582 | 0.040593 | 0.047345 | -0.033427 | 0.010303 | 0.000000 | -0.002506 | -0.000230 | -0.006841 | 0.0 | -0.006710 | -0.001683 | 0.011561 | 0.089933 | 0.070656 | 0.069578 | -0.096715 | -0.059686 | -0.002340 | -0.007626 | 0.107454 | 0.041296 | 0.044365 | 0.034597 | -0.013213 | -0.016275 | -0.003263 | 0.031300 | 0.013656 | 3.189332e-02 | 0.053397 | 0.085194 | -0.049204 | 9.255041e-03 | -4.406198e-16 | -0.072931 | 0.037936 |
| 1999-12-17 | -0.006716 | 0.001760 | -0.007777 | 0.0 | 0.0 | 0.000000 | 0.004049 | 0.015666 | 0.0 | 0.0 | 0.017015 | 0.073383 | -0.005637 | 0.033335 | 0.049056 | 0.052026 | -0.033061 | 0.030583 | 0.000000 | -0.002046 | 0.000038 | -0.004004 | 0.0 | -0.005842 | 0.008547 | 0.016955 | 0.092603 | 0.067270 | 0.074640 | -0.103897 | -0.059686 | -0.002340 | -0.022779 | 0.116741 | 0.046635 | 0.041920 | 0.025529 | -0.015893 | -0.015911 | -0.005643 | 0.021096 | 0.006184 | 2.727066e-02 | 0.051184 | 0.087769 | -0.064504 | 3.134760e-02 | 1.177610e-02 | -0.095234 | 0.032427 |
| 1999-12-20 | -0.010160 | -0.001682 | -0.000885 | 0.0 | 0.0 | 0.000000 | -0.001909 | 0.009245 | 0.0 | 0.0 | 0.017581 | 0.072012 | -0.009116 | 0.029676 | 0.055017 | 0.058351 | -0.028240 | 0.046758 | 0.000000 | 0.000143 | 0.004072 | -0.003243 | 0.0 | -0.005456 | 0.010384 | 0.019926 | 0.084122 | 0.060461 | 0.079558 | -0.094056 | -0.057926 | -0.002340 | -0.024012 | 0.111317 | 0.048405 | 0.034552 | 0.018888 | -0.022164 | -0.013361 | -0.005941 | 0.009990 | -0.002463 | 2.727066e-02 | 0.037458 | 0.074926 | -0.051374 | 4.957352e-02 | 3.344288e-02 | -0.108754 | 0.034058 |
| 1999-12-21 | -0.009568 | 0.001270 | 0.001542 | 0.0 | 0.0 | 0.000000 | 0.001223 | 0.022738 | 0.0 | 0.0 | 0.019897 | 0.080497 | -0.009116 | 0.033642 | 0.046367 | 0.049064 | -0.019231 | 0.043853 | 0.000000 | 0.000836 | 0.005690 | -0.007764 | 0.0 | -0.008156 | 0.003443 | 0.009307 | 0.083674 | 0.057443 | 0.075230 | -0.052505 | -0.047846 | -0.002340 | -0.009064 | 0.107799 | 0.032332 | 0.027998 | 0.015964 | -0.016788 | -0.008290 | 0.001776 | 0.022111 | 0.002469 | 2.267445e-02 | 0.041284 | 0.076819 | -0.057917 | 4.957352e-02 | -8.074367e-02 | -0.108754 | 0.026747 |
| 1999-12-22 | -0.009766 | 0.001071 | 0.005463 | 0.0 | 0.0 | 0.000000 | 0.002007 | 0.024800 | 0.0 | 0.0 | 0.016285 | 0.088800 | -0.008482 | 0.051278 | 0.047984 | 0.069496 | 0.002108 | 0.042255 | 0.000184 | 0.001182 | 0.006230 | 0.003262 | 0.0 | -0.007096 | 0.007902 | 0.011387 | 0.057781 | 0.027993 | 0.058148 | -0.021088 | -0.048528 | -0.015135 | 0.015056 | 0.112228 | 0.056642 | 0.054202 | 0.033776 | -0.021264 | -0.008652 | 0.002071 | 0.014014 | -0.003693 | 2.267445e-02 | 0.019091 | 0.052209 | -0.066159 | 7.011214e-02 | -1.063375e-01 | -0.108754 | 0.028771 |
| 1999-12-23 | -0.015194 | -0.004527 | 0.004261 | 0.0 | 0.0 | 0.000000 | -0.001284 | 0.040459 | 0.0 | 0.0 | 0.028903 | 0.141231 | -0.026303 | 0.076650 | 0.065232 | 0.097409 | 0.002108 | 0.049631 | 0.000276 | 0.001875 | 0.007311 | -0.002820 | 0.0 | -0.007674 | 0.000030 | 0.008615 | 0.079630 | 0.042417 | 0.066070 | -0.002505 | -0.049229 | -0.015135 | 0.006372 | 0.118212 | 0.055472 | 0.053961 | 0.035828 | -0.019023 | -0.004325 | 0.007664 | 0.006983 | -0.007371 | 2.038425e-02 | 0.019091 | 0.049121 | -0.065052 | 2.094561e-02 | -7.619713e-02 | -0.107066 | 0.020496 |
| 1999-12-24 | -0.012919 | -0.004527 | 0.004261 | 0.0 | 0.0 | 0.000000 | -0.001284 | 0.040459 | 0.0 | 0.0 | 0.033588 | 0.141231 | -0.026303 | 0.091136 | 0.065232 | 0.097409 | -0.001501 | 0.083227 | 0.000276 | 0.001875 | 0.007311 | -0.003206 | 0.0 | -0.007674 | 0.000030 | 0.008615 | 0.080530 | 0.042417 | 0.066070 | -0.002505 | -0.049229 | -0.015135 | 0.006372 | 0.118212 | 0.055472 | 0.069435 | 0.026564 | -0.019023 | -0.004325 | 0.007664 | 0.006983 | -0.007371 | 2.038425e-02 | 0.019091 | 0.049121 | -0.065052 | 2.094561e-02 | -7.619713e-02 | -0.107066 | 0.020496 |
| 1999-12-27 | -0.013315 | -0.002469 | -0.001490 | 0.0 | 0.0 | 0.000000 | 0.001693 | 0.038599 | 0.0 | 0.0 | 0.033588 | 0.149890 | -0.026303 | 0.086506 | 0.059885 | 0.103571 | 0.002690 | 0.083227 | -0.000276 | 0.001182 | 0.006500 | -0.003206 | 0.0 | -0.008444 | -0.000144 | 0.007404 | 0.080530 | 0.060059 | 0.084014 | 0.040127 | -0.044729 | -0.015135 | 0.001646 | 0.129295 | 0.054300 | 0.069530 | 0.026854 | -0.019023 | -0.005046 | 0.004433 | 0.018055 | -0.006146 | 2.038425e-02 | 0.037458 | 0.066670 | -0.079480 | 1.251465e-02 | -6.880187e-02 | -0.113898 | 0.038347 |
| 1999-12-28 | -0.009766 | 0.004323 | -0.002198 | 0.0 | 0.0 | 0.007391 | 0.009264 | 0.039273 | 0.0 | 0.0 | 0.033588 | 0.139680 | -0.026303 | 0.079541 | 0.042981 | 0.092428 | 0.012125 | 0.090569 | -0.000276 | 0.002453 | 0.008664 | -0.003206 | 0.0 | -0.005745 | 0.011873 | 0.013646 | 0.080530 | 0.078580 | 0.098821 | 0.008828 | -0.038880 | -0.015135 | 0.015298 | 0.129750 | 0.054886 | 0.069530 | 0.026854 | -0.041207 | -0.005046 | 0.004728 | 0.017043 | -0.009816 | 2.267445e-02 | 0.038006 | 0.071012 | -0.076694 | 3.515712e-02 | -9.492794e-02 | -0.113898 | 0.037119 |
| 1999-12-29 | -0.009465 | 0.005414 | -0.000378 | 0.0 | 0.0 | 0.002963 | 0.010529 | 0.041637 | 0.0 | 0.0 | 0.039158 | 0.141753 | -0.026303 | 0.079758 | 0.048237 | 0.100643 | 0.012289 | 0.071236 | -0.000276 | 0.001413 | 0.007041 | -0.004896 | 0.0 | -0.005649 | 0.013437 | 0.013820 | 0.089933 | 0.065472 | 0.093272 | -0.001670 | -0.035790 | -0.015135 | 0.022512 | 0.141910 | 0.062481 | 0.065499 | 0.046017 | -0.050871 | -0.004325 | 0.006488 | 0.019067 | -0.004920 | 2.038425e-02 | 0.045533 | 0.080375 | -0.067811 | 2.566038e-02 | -8.655975e-02 | -0.113898 | 0.023112 |
window
20
# Function to calculate rebalanced weights based on 12-day volatility
def calculate_rebalanced_weights_volatility(df, window):
# Calculate rolling standard deviation for each asset
rolling_vol = df.diff().rolling(window=window).std().fillna(0)
small_constant = 1e-8 # Small constant to avoid division by zero
# Calculate inverse volatility, avoiding division by zero by adding small constant
# Only consider non-zero volatilities in the weight calculation
inverse_volatility = 1 / (rolling_vol + small_constant)
inverse_volatility[rolling_vol == 0] = 0 # Set inverse volatility to zero where rolling volatility is zero
# Sum of inverse volatilities (excluding those set to zero)
sum_inverse_volatility = inverse_volatility.sum(axis=1)
# Initialize daily weights DataFrame
daily_weights = pd.DataFrame(index=df.index, columns=df.columns)
# Assign weights daily based on non-zero inverse volatility
for day in range(len(daily_weights)):
daily_weights.iloc[day] = inverse_volatility.iloc[day] / sum_inverse_volatility.iloc[day]
return daily_weights
# Ensure the DataFrame index is in datetime format
combined_df_SMA_bands_cleaned_vol.index = pd.to_datetime(combined_df_SMA_bands_cleaned_vol.index)
# Calculate daily rebalanced weights based on volatility using the full dataset
weights_SMA_bands_vol = calculate_rebalanced_weights_volatility(combined_df_SMA_bands_cleaned_vol, window)
# Starting calculation from the start date
#start_date = '2000-01-01'
# Filter the weights and returns dataframes from the start date
weights_SMA_bands_vol_from_start = weights_SMA_bands_vol[weights_SMA_bands_vol.index >= start_date]
daily_log_returns_SMA_bands_vol = combined_df_SMA_bands_cleaned_vol.diff().fillna(0)[combined_df_SMA_bands_cleaned_vol.index >= start_date]
# Calculate portfolio log returns using the new weights
portfolio_SMA_bands_log_returns_vol = (daily_log_returns_SMA_bands_vol * weights_SMA_bands_vol_from_start).sum(axis=1)
portfolio_SMA_bands_simple_returns_vol = np.exp(portfolio_SMA_bands_log_returns_vol) - 1
portfolio_SMA_bands_cumulative_simple_returns_vol = (1 + portfolio_SMA_bands_simple_returns_vol).cumprod() - 1
# Plot the performance
trace = go.Scatter(x=weights_SMA_bands_vol_from_start.index, y=portfolio_SMA_bands_cumulative_simple_returns_vol, mode='lines', name='Cumulative Simple Returns with Daily Rebalancing')
data = [trace]
layout = go.Layout(title='Inverse Volatility Weighted Portfolio SMA with Bands with Daily Rebalancing - from 2000', xaxis=dict(title='Days'), yaxis=dict(title='Simple Return'))
fig = go.Figure(data=data, layout=layout)
fig.show()
# Save the weights to an Excel file
weights_SMA_bands_vol_from_start.to_excel('rebalanced_weights_volatility_SMA_bands.xlsx')
<ipython-input-77-1dd74f5067e8>:48: UserWarning: Pandas requires version '1.4.3' or newer of 'xlsxwriter' (version '1.3.8' currently installed).
#strategy_start = '2000-01-01'
window_history = window + 10 # Define the window size as 15 days + 10 to have enough history
start_date = pd.to_datetime(strategy_start) # Convert start_date to datetime object
adjusted_start_date = start_date - pd.DateOffset(days=window_history) # Calculate adjusted start date
# Dictionary to store the filtered DataFrames
filtered_dfs = {}
# Loop through each header in new_headers
for header in new_headers:
# Access the DataFrame for the current header
df = strategy_TSMOM[header]
# Check if the DataFrame has an index that includes the range we need
if df.index.min() <= adjusted_start_date and df.index.max() >= start_date:
# Filter the DataFrame to show data from adjusted_start_date to start_date
filtered_df = df.loc[adjusted_start_date:start_date]
# Store the filtered DataFrame in the dictionary
filtered_dfs[header] = filtered_df
#initial_investment = 1000000
#strategy_start = '2000-01-01'
for header in new_headers:
# Running total of log returns based on trade signals
running_total = float(0)
for date, row in filtered_dfs[header].iterrows():
# Update running total based on trade signals
if row[f'Signal_TSMOM_{TSMOM_window_month}_shifted'] == 1: # Buy signal
running_total += row['Log_Return']
elif row[f'Signal_TSMOM_{TSMOM_window_month}_shifted'] == -1: # Sell signal
running_total -= row['Log_Return']
# Calculate cumulative returns
cumulative_log_return = np.exp(running_total) - 1
# Store the running total and the cumulative returns in the DataFrame
filtered_dfs[header].loc[date, 'Cumulative_Log_Returns'] = running_total
filtered_dfs[header].loc[date, 'Total_Log_Return'] = initial_investment * (1 + cumulative_log_return)
<ipython-input-79-4d91684a8daf>:19: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy <ipython-input-79-4d91684a8daf>:20: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
# Assuming new_headers and filtered_dfs are already defined and populated
# List to hold the data series for total log returns
data_series_list_total_log_return = []
# Extract 'Total_Log_Return' from each filtered DataFrame and rename it uniquely
for header in new_headers:
if 'Cumulative_Log_Returns' in filtered_dfs[header].columns:
# Extract the series and rename it with its asset name
series = filtered_dfs[header]['Cumulative_Log_Returns'].rename(header)
data_series_list_total_log_return.append(series)
# Combine all the series into a single DataFrame
combined_df_total_log_return = pd.concat(data_series_list_total_log_return, axis=1, join='outer')
# Forward fill missing values, if necessary
combined_df_filled_total_log_return = combined_df_total_log_return.ffill()
# Drop rows where any NaN values still exist (likely at the start)
combined_df_cleaned_total_log_return = combined_df_filled_total_log_return.dropna()
# Concatenate the two DataFrames
combined_df_TSMOM_cleaned_vol = pd.concat([combined_df_cleaned_total_log_return, combined_df_TSMOM_cleaned])
# Check the concatenated result
combined_df_TSMOM_cleaned_vol.head(20)
| USD Future | EUR Future (USD) | JPY Future (USD) | GBP Future (USD) | GBP Future (EUR) | CAD Future (USD) | CHF Future (USD) | S&P 500 | Nasdaq 100 | S&P Canada 60 | FTSE 100 | DAX | SMI | CAC - 40 | IBEX 35 | Euro Stoxx 50 | Nikkei 225 | Hang Seng Index | US 2-year | US 5-year | US 10-year | Long Gilt (10 year) | Euro-Schatz-Futures (2 year) | Euro-Bobl-Future (5 year) | Euro-Bund-Future (10 year) | Euro-Buxl-Future (30 year) | Brent Crude Oil | WTI Crude Oil | Heating Oil | Natural Gas | Gold | Silver | Platinum | Palladium | Copper | Nickel | Zinc | Lean hogs | Live cattle | Feeder cattle | Wheat | Corn | Oat | Soybeans | Soybean oil | Frozen orange juice | Cocoa | Coffee | Sugar No.11 | Cotton No.2 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Date | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 1999-12-02 | 0.00000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.000000 |
| 1999-12-03 | 0.00000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.000000 |
| 1999-12-06 | 0.00000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.000000 |
| 1999-12-07 | 0.00000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.000000 |
| 1999-12-08 | 0.00000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.000000 |
| 1999-12-09 | 0.00000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.000000 |
| 1999-12-10 | 0.00000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.000000 |
| 1999-12-13 | 0.00000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.000000 |
| 1999-12-14 | 0.00000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.000000 |
| 1999-12-15 | 0.00000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.000000 |
| 1999-12-16 | 0.00000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.000000 |
| 1999-12-17 | 0.00000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.000000 |
| 1999-12-20 | 0.00000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.000000 |
| 1999-12-21 | 0.00000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.000000 |
| 1999-12-22 | 0.00000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.000000 |
| 1999-12-23 | 0.00000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.000000 |
| 1999-12-24 | 0.00000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.000000 |
| 1999-12-27 | 0.00000 | 0.002058 | -0.005751 | -0.002000 | 0.0 | 0.007446 | 0.002977 | -0.001861 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | -0.004630 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000094 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.000000 |
| 1999-12-28 | 0.00355 | 0.008849 | -0.006459 | -0.000600 | 0.0 | 0.014837 | 0.010547 | -0.001186 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | -0.011595 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000094 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | -0.002786 | 0.0 | 0.0 | 0.0 | 0.000000 |
| 1999-12-29 | 0.00385 | 0.009941 | -0.004639 | -0.002466 | 0.0 | 0.010409 | 0.011813 | 0.001178 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | -0.011378 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | -0.003936 | 0.019164 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | -0.011669 | 0.0 | 0.0 | 0.0 | -0.014007 |
window
20
# Function to calculate rebalanced weights based on 12-day volatility
def calculate_rebalanced_weights_volatility(df, window):
# Calculate rolling standard deviation for each asset
rolling_vol = df.diff().rolling(window=window).std().fillna(0)
small_constant = 1e-8 # Small constant to avoid division by zero
# Calculate inverse volatility, avoiding division by zero by adding small constant
# Only consider non-zero volatilities in the weight calculation
inverse_volatility = 1 / (rolling_vol + small_constant)
inverse_volatility[rolling_vol == 0] = 0 # Set inverse volatility to zero where rolling volatility is zero
# Sum of inverse volatilities (excluding those set to zero)
sum_inverse_volatility = inverse_volatility.sum(axis=1)
# Initialize daily weights DataFrame
daily_weights = pd.DataFrame(index=df.index, columns=df.columns)
# Assign weights daily based on non-zero inverse volatility
for day in range(len(daily_weights)):
daily_weights.iloc[day] = inverse_volatility.iloc[day] / sum_inverse_volatility.iloc[day]
return daily_weights
# Ensure the DataFrame index is in datetime format
combined_df_TSMOM_cleaned_vol.index = pd.to_datetime(combined_df_TSMOM_cleaned_vol.index)
# Calculate daily rebalanced weights based on volatility using the full dataset
weights_TSMOM_vol = calculate_rebalanced_weights_volatility(combined_df_TSMOM_cleaned_vol, window)
# Starting calculation from the start date
#start_date = '2000-01-01'
# Filter the weights and returns dataframes from the start date
weights_TSMOM_vol_from_start = weights_TSMOM_vol[weights_TSMOM_vol.index >= start_date]
daily_log_returns_TSMOM_vol = combined_df_TSMOM_cleaned_vol.diff().fillna(0)[combined_df_TSMOM_cleaned_vol.index >= start_date]
# Calculate portfolio log returns using the new weights
portfolio_TSMOM_log_returns_vol = (daily_log_returns_TSMOM_vol * weights_TSMOM_vol_from_start).sum(axis=1)
portfolio_TSMOM_simple_returns_vol = np.exp(portfolio_TSMOM_log_returns_vol) - 1
portfolio_TSMOM_cumulative_simple_returns_vol = (1 + portfolio_TSMOM_simple_returns_vol).cumprod() - 1
# Plot the performance
trace = go.Scatter(x=weights_TSMOM_vol_from_start.index, y=portfolio_TSMOM_cumulative_simple_returns_vol, mode='lines', name='Cumulative Simple Returns with Daily Rebalancing')
data = [trace]
layout = go.Layout(title='Inverse Volatility Weighted Portfolio TSMOM with Daily Rebalancing - from 2000', xaxis=dict(title='Days'), yaxis=dict(title='Simple Return'))
fig = go.Figure(data=data, layout=layout)
fig.show()
# Save the weights to an Excel file
weights_TSMOM_vol_from_start.to_excel('rebalanced_weights_volatility_TSMOM.xlsx')
<ipython-input-82-7271abda57fc>:48: UserWarning: Pandas requires version '1.4.3' or newer of 'xlsxwriter' (version '1.3.8' currently installed).
#strategy_start = '2000-01-01'
window_history = window + 10 # Define the window size as 15 days + 10 to have enough history
start_date = pd.to_datetime(strategy_start) # Convert start_date to datetime object
adjusted_start_date = start_date - pd.DateOffset(days=window_history) # Calculate adjusted start date
# Dictionary to store the filtered DataFrames
filtered_dfs = {}
# Loop through each header in new_headers
for header in new_headers:
# Access the DataFrame for the current header
df = strategy_RAMOM[header]
# Check if the DataFrame has an index that includes the range we need
if df.index.min() <= adjusted_start_date and df.index.max() >= start_date:
# Filter the DataFrame to show data from adjusted_start_date to start_date
filtered_df = df.loc[adjusted_start_date:start_date]
# Store the filtered DataFrame in the dictionary
filtered_dfs[header] = filtered_df
#initial_investment = 1000000
#strategy_start = '2000-01-01'
for header in new_headers:
# Running total of log returns based on trade signals
running_total = float(0)
for date, row in filtered_dfs[header].iterrows():
# Update running total based on trade signals
if row[f'Signal_RAMOM_{RAMOM_window_month}_shifted'] == 1: # Buy signal
running_total += row['Log_Return']
elif row[f'Signal_RAMOM_{RAMOM_window_month}_shifted'] == -1: # Sell signal
running_total -= row['Log_Return']
# Calculate cumulative returns
cumulative_log_return = np.exp(running_total) - 1
# Store the running total and the cumulative returns in the DataFrame
filtered_dfs[header].loc[date, 'Cumulative_Log_Returns'] = running_total
filtered_dfs[header].loc[date, 'Total_Log_Return'] = initial_investment * (1 + cumulative_log_return)
<ipython-input-84-098330b9dcc0>:19: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy <ipython-input-84-098330b9dcc0>:20: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
# Assuming new_headers and filtered_dfs are already defined and populated
# List to hold the data series for total log returns
data_series_list_total_log_return = []
# Extract 'Total_Log_Return' from each filtered DataFrame and rename it uniquely
for header in new_headers:
if 'Cumulative_Log_Returns' in filtered_dfs[header].columns:
# Extract the series and rename it with its asset name
series = filtered_dfs[header]['Cumulative_Log_Returns'].rename(header)
data_series_list_total_log_return.append(series)
# Combine all the series into a single DataFrame
combined_df_total_log_return = pd.concat(data_series_list_total_log_return, axis=1, join='outer')
# Forward fill missing values, if necessary
combined_df_filled_total_log_return = combined_df_total_log_return.ffill()
# Drop rows where any NaN values still exist (likely at the start)
combined_df_cleaned_total_log_return = combined_df_filled_total_log_return.dropna()
# Concatenate the two DataFrames
combined_df_RAMOM_cleaned_vol = pd.concat([combined_df_cleaned_total_log_return, combined_df_RAMOM_cleaned])
# Check the concatenated result
combined_df_RAMOM_cleaned_vol.head(20)
| USD Future | EUR Future (USD) | JPY Future (USD) | GBP Future (USD) | GBP Future (EUR) | CAD Future (USD) | CHF Future (USD) | S&P 500 | Nasdaq 100 | S&P Canada 60 | FTSE 100 | DAX | SMI | CAC - 40 | IBEX 35 | Euro Stoxx 50 | Nikkei 225 | Hang Seng Index | US 2-year | US 5-year | US 10-year | Long Gilt (10 year) | Euro-Schatz-Futures (2 year) | Euro-Bobl-Future (5 year) | Euro-Bund-Future (10 year) | Euro-Buxl-Future (30 year) | Brent Crude Oil | WTI Crude Oil | Heating Oil | Natural Gas | Gold | Silver | Platinum | Palladium | Copper | Nickel | Zinc | Lean hogs | Live cattle | Feeder cattle | Wheat | Corn | Oat | Soybeans | Soybean oil | Frozen orange juice | Cocoa | Coffee | Sugar No.11 | Cotton No.2 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Date | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 1999-12-02 | 0.004590 | 0.006265 | 0.000000 | 4.709523e-04 | 0.005719 | -4.507896e-03 | 0.004931 | 0.006932 | 0.032159 | 0.006189 | 0.001339 | 0.000488 | 0.001752 | -0.005761 | 0.009062 | -0.001177 | -0.008317 | 0.007219 | 0.000413 | 9.188010e-04 | -0.001871 | -0.005999 | -0.001356 | -0.002393 | 0.008732 | -0.008788 | 0.038264 | 0.032342 | 0.032365 | -0.028020 | 0.016580 | 0.016017 | -0.005473 | 0.012976 | 0.008719 | 0.011721 | -0.012531 | 0.001436 | -0.004316 | -0.000593 | 0.017043 | 0.001234 | -6.706804e-03 | 0.006853 | 0.016702 | 0.009761 | 2.330022e-02 | 3.823561e-02 | 0.001726 | 0.003552 |
| 1999-12-03 | 0.004692 | 0.006566 | -0.000616 | 1.544988e-17 | 0.006513 | -3.003005e-03 | 0.002384 | 0.024825 | 0.051725 | 0.023781 | 0.014686 | 0.025189 | 0.009509 | 0.011870 | 0.022211 | 0.018092 | -0.006757 | 0.026087 | -0.001191 | -2.865824e-03 | 0.002934 | -0.009766 | -0.000290 | 0.000287 | 0.005635 | -0.001889 | 0.037795 | 0.031929 | 0.028755 | 0.026250 | 0.034136 | 0.014052 | -0.008097 | 0.018845 | -0.008030 | 0.043510 | 0.006418 | 0.008575 | -0.005046 | 0.004728 | 0.035411 | 0.006184 | -8.930772e-03 | 0.007379 | 0.026386 | 0.013333 | 3.754547e-02 | 9.610882e-02 | -0.037425 | 0.017286 |
| 1999-12-06 | -0.009850 | -0.013086 | -0.004212 | -1.130333e-02 | -0.000952 | 4.553649e-17 | -0.014956 | 0.016267 | 0.061287 | 0.034730 | 0.022056 | 0.049985 | 0.012402 | 0.041281 | 0.022211 | 0.052100 | -0.008525 | 0.044097 | -0.001511 | -3.323595e-03 | 0.004530 | 0.006353 | 0.000584 | 0.002783 | -0.021539 | 0.010580 | 0.071039 | 0.064272 | 0.047223 | 0.073240 | 0.048068 | 0.012092 | -0.010256 | 0.039639 | -0.010483 | 0.051454 | 0.019138 | 0.003828 | -0.006482 | 0.000296 | 0.015023 | -0.008595 | -2.217666e-02 | -0.001050 | 0.033687 | 0.008739 | 2.330022e-02 | 2.788417e-02 | -0.078387 | 0.020496 |
| 1999-12-07 | -0.012128 | -0.015335 | 0.002352 | -1.462317e-02 | -0.000639 | 4.553649e-17 | -0.016355 | 0.009406 | 0.063470 | 0.037990 | 0.017793 | 0.050992 | 0.007651 | 0.045323 | 0.059892 | 0.050696 | 0.003030 | 0.040656 | -0.002015 | -5.266786e-03 | 0.007716 | 0.015174 | 0.000195 | 0.003166 | -0.022935 | 0.014139 | 0.055478 | 0.047722 | 0.024201 | 0.052328 | 0.022519 | 0.004799 | -0.009064 | 0.033908 | 0.004972 | 0.012733 | 0.003426 | -0.003355 | -0.004685 | 0.003548 | 0.023128 | -0.002463 | -1.777751e-02 | -0.008886 | 0.023344 | 0.002066 | -6.885499e-03 | 2.079859e-02 | -0.052358 | 0.005927 |
| 1999-12-08 | -0.013716 | -0.017961 | -0.003079 | -1.674210e-02 | -0.001278 | -3.003005e-03 | -0.018387 | 0.002141 | 0.048886 | 0.024765 | 0.013134 | 0.050758 | 0.004459 | 0.045421 | 0.059892 | 0.057004 | -0.015532 | 0.030574 | -0.001420 | -3.781156e-03 | 0.006390 | 0.015793 | -0.000388 | 0.001727 | -0.025188 | 0.011259 | 0.066943 | 0.059657 | 0.036606 | 0.044869 | 0.027088 | 0.010135 | -0.008816 | 0.036842 | 0.008719 | 0.018412 | -0.001718 | -0.006233 | 0.003567 | 0.011185 | 0.039539 | 0.013656 | -6.706804e-03 | 0.008438 | 0.033093 | -0.009334 | 6.071532e-18 | -1.346433e-02 | -0.045791 | 0.013685 |
| 1999-12-09 | -0.010343 | -0.011718 | 0.001225 | -1.462317e-02 | 0.002849 | 5.594483e-17 | -0.012299 | 0.005686 | 0.049675 | 0.024428 | 0.020884 | 0.044052 | -0.000254 | 0.048473 | 0.058859 | 0.056264 | -0.020567 | 0.060987 | -0.001877 | -4.809904e-03 | 0.007981 | 0.019453 | 0.000584 | 0.004411 | -0.022890 | 0.013631 | 0.042011 | 0.044869 | 0.013493 | 0.046182 | 0.040551 | 0.012504 | -0.001372 | 0.034150 | 0.003099 | 0.024182 | 0.004712 | -0.017375 | -0.002164 | 0.007958 | 0.043684 | 0.027502 | -4.477880e-03 | 0.035280 | 0.064762 | -0.001551 | -2.051588e-02 | -6.798358e-02 | -0.057350 | 0.017286 |
| 1999-12-10 | -0.003536 | -0.002568 | 0.001944 | -1.216755e-02 | 0.009558 | 1.500375e-03 | -0.002857 | 0.010113 | 0.062068 | 0.042192 | 0.027664 | 0.033574 | -0.016315 | 0.028262 | 0.038236 | 0.033632 | -0.017422 | 0.059040 | -0.002746 | -7.320175e-03 | 0.012739 | 0.024332 | 0.001554 | 0.006992 | -0.021551 | 0.021218 | 0.017879 | 0.009136 | -0.015226 | -0.021906 | 0.038058 | 0.010135 | -0.012407 | 0.057995 | 0.013099 | 0.015262 | -0.003657 | -0.026665 | -0.015911 | -0.002075 | 0.039539 | 0.022445 | -4.477880e-03 | 0.032021 | 0.066023 | -0.021395 | -8.256928e-03 | -2.986440e-02 | -0.045791 | 0.016283 |
| 1999-12-13 | -0.004234 | -0.004428 | -0.006763 | -1.422537e-02 | 0.009875 | 3.003005e-03 | -0.004106 | 0.010287 | 0.072459 | 0.046792 | 0.024431 | 0.035195 | -0.018300 | 0.035801 | 0.042070 | 0.037825 | -0.032808 | 0.055331 | -0.002106 | -6.179924e-03 | 0.011155 | 0.023580 | 0.000778 | 0.004698 | -0.014199 | 0.015322 | 0.022657 | 0.015041 | 0.007606 | -0.047337 | 0.034136 | 0.010546 | 0.000608 | 0.074471 | 0.006217 | 0.010476 | -0.000893 | -0.033914 | -0.019564 | -0.003263 | 0.056223 | 0.035135 | 9.006133e-03 | 0.053949 | 0.080686 | -0.037343 | 3.277447e-02 | -5.095131e-02 | -0.044143 | 0.015082 |
| 1999-12-14 | 0.002560 | 0.004031 | -0.010122 | -6.503325e-03 | 0.010508 | 4.507896e-03 | 0.003735 | 0.002426 | 0.052512 | 0.037911 | 0.016421 | 0.043739 | -0.023086 | 0.036612 | 0.038449 | 0.039288 | -0.036059 | 0.046346 | 0.000138 | -1.605873e-03 | 0.003200 | 0.011770 | 0.001846 | 0.002591 | -0.003716 | 0.003254 | 0.047605 | 0.028823 | 0.028136 | -0.077178 | 0.034504 | -0.002340 | -0.001272 | 0.087685 | -0.002481 | 0.014131 | 0.007152 | -0.014557 | -0.016275 | -0.003263 | 0.041609 | 0.018669 | 4.336809e-17 | 0.049525 | 0.074272 | -0.052461 | 2.897399e-02 | -6.594041e-02 | -0.020578 | 0.012686 |
| 1999-12-15 | 0.002756 | 0.002649 | -0.012164 | -2.015859e-03 | 0.004635 | 6.015056e-03 | 0.002164 | 0.004879 | 0.068359 | 0.044250 | 0.002936 | 0.044478 | -0.027954 | 0.026054 | 0.027260 | 0.032383 | -0.040092 | 0.017607 | 0.000917 | -3.816392e-17 | 0.000267 | 0.010441 | 0.001069 | 0.004890 | -0.007365 | 0.010071 | 0.066031 | 0.052999 | 0.048254 | -0.038127 | 0.025319 | -0.001425 | -0.019351 | 0.087914 | -0.040108 | -0.007891 | 0.016383 | -0.006121 | -0.018101 | -0.002966 | 0.041609 | 0.018669 | 1.581952e-02 | 0.050079 | 0.074272 | -0.070027 | 1.718974e-02 | -1.929078e-02 | 0.003556 | 0.021100 |
| 1999-12-16 | -0.004234 | -0.006779 | -0.006456 | -5.500416e-03 | -0.001202 | 1.500375e-03 | -0.005509 | 0.010808 | 0.100356 | 0.052917 | 0.010410 | 0.071117 | -0.041594 | 0.037582 | 0.040593 | 0.047345 | -0.033427 | 0.010303 | 0.002110 | 2.183532e-03 | -0.004551 | 0.021724 | 0.004569 | -0.002987 | -0.001683 | -0.011561 | 0.089933 | 0.070656 | 0.069578 | -0.096715 | 0.028128 | -0.006194 | -0.014807 | 0.107454 | -0.041296 | -0.016103 | 0.034597 | -0.013213 | -0.016275 | -0.003263 | 0.031300 | 0.013656 | 3.189332e-02 | 0.053397 | 0.085194 | -0.049204 | 9.255041e-03 | -4.406198e-16 | 0.001726 | 0.037936 |
| 1999-12-17 | 0.001876 | 0.001760 | -0.007777 | -1.747312e-03 | 0.003528 | 3.003005e-03 | 0.004049 | 0.015666 | 0.109627 | 0.061833 | 0.017015 | 0.073383 | -0.040480 | 0.033335 | 0.049056 | 0.052026 | -0.033061 | 0.030583 | 0.002294 | 2.643832e-03 | -0.004283 | 0.024561 | 0.004375 | -0.003855 | 0.008547 | -0.006166 | 0.092603 | 0.067270 | 0.074640 | -0.103897 | 0.022174 | -0.008418 | -0.029960 | 0.116741 | -0.046635 | -0.013658 | 0.025529 | -0.015893 | -0.015911 | -0.005643 | 0.021096 | 0.006184 | 2.727066e-02 | 0.051184 | 0.087769 | -0.064504 | 3.134760e-02 | 1.177610e-02 | -0.020578 | 0.032427 |
| 1999-12-20 | -0.001569 | -0.001682 | -0.000885 | -2.351441e-03 | 0.000690 | 3.003005e-03 | -0.001909 | 0.009245 | 0.119249 | 0.063693 | 0.017581 | 0.072012 | -0.043959 | 0.029676 | 0.055017 | 0.058351 | -0.028240 | 0.046758 | 0.002892 | 4.833151e-03 | -0.000249 | 0.025323 | 0.004082 | -0.003469 | 0.010384 | -0.003195 | 0.084122 | 0.060461 | 0.079558 | -0.094056 | 0.020414 | -0.003254 | -0.031193 | 0.111317 | -0.048405 | -0.006290 | 0.018888 | -0.022164 | -0.013361 | -0.005941 | 0.009990 | -0.002463 | 2.727066e-02 | 0.037458 | 0.074926 | -0.051374 | 4.957352e-02 | 3.344288e-02 | -0.034098 | 0.034058 |
| 1999-12-21 | -0.000977 | 0.001270 | 0.001542 | -6.503325e-03 | 0.007814 | 1.500375e-03 | 0.001223 | 0.022738 | 0.162545 | 0.083635 | 0.019897 | 0.080497 | -0.034946 | 0.033642 | 0.046367 | 0.049064 | -0.019231 | 0.043853 | 0.003121 | 5.525512e-03 | 0.001369 | 0.020802 | 0.003109 | -0.006169 | 0.003443 | -0.013814 | 0.083674 | 0.057443 | 0.075230 | -0.052505 | 0.010335 | 0.003367 | -0.016245 | 0.107799 | -0.032332 | 0.000264 | 0.015964 | -0.016788 | -0.018433 | 0.001776 | 0.022111 | 0.002469 | 2.267445e-02 | 0.041284 | 0.076819 | -0.057917 | 4.957352e-02 | -8.074367e-02 | -0.027410 | 0.026747 |
| 1999-12-22 | -0.001174 | 0.001071 | 0.005463 | -3.893668e-03 | 0.004950 | 3.003005e-03 | 0.002007 | 0.024800 | 0.168224 | 0.083605 | 0.016285 | 0.088800 | -0.034312 | 0.051278 | 0.047984 | 0.069496 | 0.002108 | 0.042255 | 0.003305 | 5.871872e-03 | 0.001909 | 0.031828 | 0.003888 | -0.005109 | 0.007902 | -0.011734 | 0.057781 | 0.027993 | 0.058148 | -0.021088 | 0.011016 | 0.016161 | 0.007876 | 0.112228 | -0.056642 | -0.025940 | 0.033776 | -0.021264 | -0.018071 | 0.002071 | 0.014014 | -0.003693 | 2.267445e-02 | 0.019091 | 0.052209 | -0.066159 | 7.011214e-02 | -1.063375e-01 | -0.022265 | 0.028771 |
| 1999-12-23 | -0.006603 | -0.004527 | 0.004261 | -7.972440e-03 | 0.003528 | -2.994014e-03 | -0.001284 | 0.040459 | 0.174972 | 0.099040 | 0.028903 | 0.141231 | -0.052133 | 0.076650 | 0.065232 | 0.097409 | 0.002108 | 0.049631 | 0.003397 | 6.564953e-03 | 0.002990 | 0.025746 | 0.003693 | -0.005687 | 0.000030 | -0.014507 | 0.079630 | 0.042417 | 0.066070 | -0.002505 | 0.011717 | 0.012320 | -0.000808 | 0.118212 | -0.055472 | -0.025699 | 0.035828 | -0.019023 | -0.022398 | 0.007664 | 0.006983 | -0.007371 | 2.038425e-02 | 0.019091 | 0.049121 | -0.065052 | 2.094561e-02 | -7.619713e-02 | -0.020578 | 0.020496 |
| 1999-12-24 | -0.004328 | -0.004527 | 0.004261 | -7.972440e-03 | 0.003528 | -2.994014e-03 | -0.001284 | 0.040459 | 0.174972 | 0.104372 | 0.033588 | 0.141231 | -0.052133 | 0.091136 | 0.065232 | 0.097409 | -0.001501 | 0.083227 | 0.003397 | 6.564953e-03 | 0.002990 | 0.025360 | 0.003693 | -0.005687 | 0.000030 | -0.014507 | 0.080530 | 0.042417 | 0.066070 | -0.002505 | 0.011717 | 0.012320 | -0.000808 | 0.118212 | -0.055472 | -0.010225 | 0.026564 | -0.019023 | -0.022398 | 0.007664 | 0.006983 | -0.007371 | 2.038425e-02 | 0.019091 | 0.049121 | -0.065052 | 2.094561e-02 | -7.619713e-02 | -0.020578 | 0.020496 |
| 1999-12-27 | -0.004724 | -0.002469 | -0.001490 | -9.972308e-03 | 0.007485 | -1.044006e-02 | 0.001693 | 0.038599 | 0.173872 | 0.104372 | 0.033588 | 0.149890 | -0.050221 | 0.086506 | 0.059885 | 0.103571 | 0.002690 | 0.083227 | 0.002846 | 5.871872e-03 | 0.002179 | 0.025360 | 0.002915 | -0.006458 | -0.000144 | -0.015717 | 0.080530 | 0.060059 | 0.084014 | 0.040127 | 0.007217 | 0.013838 | -0.005534 | 0.129295 | -0.054300 | -0.010131 | 0.026854 | -0.019023 | -0.021676 | 0.004433 | 0.018055 | -0.006146 | 2.038425e-02 | 0.037458 | 0.066670 | -0.050623 | 1.251465e-02 | -6.880187e-02 | -0.027410 | 0.038347 |
| 1999-12-28 | -0.001174 | 0.004323 | -0.002198 | -8.572821e-03 | 0.012904 | -1.783108e-02 | 0.009264 | 0.039273 | 0.169054 | 0.104372 | 0.033588 | 0.139680 | -0.048769 | 0.079541 | 0.042981 | 0.092428 | 0.012125 | 0.090569 | 0.003305 | 7.142888e-03 | 0.004343 | 0.025360 | 0.003888 | -0.003758 | 0.011873 | -0.009476 | 0.080530 | 0.078580 | 0.098821 | 0.008828 | 0.001368 | 0.011408 | 0.008118 | 0.129750 | -0.053714 | -0.010131 | 0.026854 | -0.041207 | -0.021676 | 0.004728 | 0.017043 | -0.009816 | 2.267445e-02 | 0.038006 | 0.071012 | -0.053409 | 3.515712e-02 | -9.492794e-02 | -0.027410 | 0.037119 |
| 1999-12-29 | -0.000873 | 0.005414 | -0.000378 | -1.043837e-02 | 0.015943 | -1.340303e-02 | 0.010529 | 0.041637 | 0.202178 | 0.116188 | 0.039158 | 0.141753 | -0.053041 | 0.079758 | 0.048237 | 0.100643 | 0.012289 | 0.071236 | 0.002662 | 6.102846e-03 | 0.002720 | 0.023670 | 0.003693 | -0.003662 | 0.013437 | -0.009302 | 0.089933 | 0.065472 | 0.093272 | -0.001670 | -0.001721 | 0.043825 | 0.015332 | 0.141910 | -0.046120 | -0.014161 | 0.046017 | -0.050871 | -0.022398 | 0.006488 | 0.019067 | -0.004920 | 2.038425e-02 | 0.045533 | 0.080375 | -0.062293 | 2.566038e-02 | -8.655975e-02 | -0.063841 | 0.023112 |
window
20
# Function to calculate rebalanced weights based on 12-day volatility
def calculate_rebalanced_weights_volatility(df, window):
# Calculate rolling standard deviation for each asset
rolling_vol = df.diff().rolling(window=window).std().fillna(0)
small_constant = 1e-8 # Small constant to avoid division by zero
# Calculate inverse volatility, avoiding division by zero by adding small constant
# Only consider non-zero volatilities in the weight calculation
inverse_volatility = 1 / (rolling_vol + small_constant)
inverse_volatility[rolling_vol == 0] = 0 # Set inverse volatility to zero where rolling volatility is zero
# Sum of inverse volatilities (excluding those set to zero)
sum_inverse_volatility = inverse_volatility.sum(axis=1)
# Initialize daily weights DataFrame
daily_weights = pd.DataFrame(index=df.index, columns=df.columns)
# Assign weights daily based on non-zero inverse volatility
for day in range(len(daily_weights)):
daily_weights.iloc[day] = inverse_volatility.iloc[day] / sum_inverse_volatility.iloc[day]
return daily_weights
# Ensure the DataFrame index is in datetime format
combined_df_RAMOM_cleaned_vol.index = pd.to_datetime(combined_df_RAMOM_cleaned_vol.index)
# Calculate daily rebalanced weights based on volatility using the full dataset
weights_RAMOM_vol = calculate_rebalanced_weights_volatility(combined_df_RAMOM_cleaned_vol, window)
# Starting calculation from the start date
#start_date = '2000-01-01'
# Filter the weights and returns dataframes from the start date
weights_RAMOM_vol_from_start = weights_RAMOM_vol[weights_RAMOM_vol.index >= start_date]
daily_log_returns_RAMOM_vol = combined_df_RAMOM_cleaned_vol.diff().fillna(0)[combined_df_RAMOM_cleaned_vol.index >= start_date]
# Calculate portfolio log returns using the new weights
portfolio_RAMOM_log_returns_vol = (daily_log_returns_RAMOM_vol * weights_RAMOM_vol_from_start).sum(axis=1)
portfolio_RAMOM_simple_returns_vol = np.exp(portfolio_RAMOM_log_returns_vol) - 1
portfolio_RAMOM_cumulative_simple_returns_vol = (1 + portfolio_RAMOM_simple_returns_vol).cumprod() - 1
# Plot the performance
trace = go.Scatter(x=weights_RAMOM_vol_from_start.index, y=portfolio_RAMOM_cumulative_simple_returns_vol, mode='lines', name='Cumulative Simple Returns with Daily Rebalancing')
data = [trace]
layout = go.Layout(title='Inverse Volatility Weighted Portfolio RAMOM with Daily Rebalancing - from 2000', xaxis=dict(title='Days'), yaxis=dict(title='Simple Return'))
fig = go.Figure(data=data, layout=layout)
fig.show()
# Save the weights to an Excel file
weights_RAMOM_vol_from_start.to_excel('rebalanced_weights_volatility_RAMOM.xlsx')
<ipython-input-87-fbd277bcf19a>:48: UserWarning: Pandas requires version '1.4.3' or newer of 'xlsxwriter' (version '1.3.8' currently installed).
#strategy_start = '2000-01-01'
window_history = window + 10 # Define the window size as 15 days + 10 to have enough history
start_date = pd.to_datetime(strategy_start) # Convert start_date to datetime object
adjusted_start_date = start_date - pd.DateOffset(days=window_history) # Calculate adjusted start date
# Dictionary to store the filtered DataFrames
filtered_dfs = {}
# Loop through each header in new_headers
for header in new_headers:
# Access the DataFrame for the current header
df = strategy_kalman[header]
# Check if the DataFrame has an index that includes the range we need
if df.index.min() <= adjusted_start_date and df.index.max() >= start_date:
# Filter the DataFrame to show data from adjusted_start_date to start_date
filtered_df = df.loc[adjusted_start_date:start_date]
# Store the filtered DataFrame in the dictionary
filtered_dfs[header] = filtered_df
#initial_investment = 1000000
#strategy_start = '2000-01-01'
for header in new_headers:
# Running total of log returns based on trade signals
running_total = float(0)
for date, row in filtered_dfs[header].iterrows():
# Update running total based on trade signals
if row['Signal_Kalman_Filter_shifted'] == 1: # Buy signal
running_total += row['Log_Return']
elif row['Signal_Kalman_Filter_shifted'] == -1: # Sell signal
running_total -= row['Log_Return']
# Calculate cumulative returns
cumulative_log_return = np.exp(running_total) - 1
# Store the running total and the cumulative returns in the DataFrame
filtered_dfs[header].loc[date, 'Cumulative_Log_Returns'] = running_total
filtered_dfs[header].loc[date, 'Total_Log_Return'] = initial_investment * (1 + cumulative_log_return)
<ipython-input-89-0dca73fa82fc>:19: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy <ipython-input-89-0dca73fa82fc>:20: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
# Assuming new_headers and filtered_dfs are already defined and populated
# List to hold the data series for total log returns
data_series_list_total_log_return = []
# Extract 'Total_Log_Return' from each filtered DataFrame and rename it uniquely
for header in new_headers:
if 'Cumulative_Log_Returns' in filtered_dfs[header].columns:
# Extract the series and rename it with its asset name
series = filtered_dfs[header]['Cumulative_Log_Returns'].rename(header)
data_series_list_total_log_return.append(series)
# Combine all the series into a single DataFrame
combined_df_total_log_return = pd.concat(data_series_list_total_log_return, axis=1, join='outer')
# Forward fill missing values, if necessary
combined_df_filled_total_log_return = combined_df_total_log_return.ffill()
# Drop rows where any NaN values still exist (likely at the start)
combined_df_cleaned_total_log_return = combined_df_filled_total_log_return.dropna()
# Concatenate the two DataFrames
combined_df_kalman_cleaned_vol = pd.concat([combined_df_cleaned_total_log_return, combined_df_kalman_cleaned])
# Check the concatenated result
combined_df_kalman_cleaned_vol.head(20)
| USD Future | EUR Future (USD) | JPY Future (USD) | GBP Future (USD) | GBP Future (EUR) | CAD Future (USD) | CHF Future (USD) | S&P 500 | Nasdaq 100 | S&P Canada 60 | FTSE 100 | DAX | SMI | CAC - 40 | IBEX 35 | Euro Stoxx 50 | Nikkei 225 | Hang Seng Index | US 2-year | US 5-year | US 10-year | Long Gilt (10 year) | Euro-Schatz-Futures (2 year) | Euro-Bobl-Future (5 year) | Euro-Bund-Future (10 year) | Euro-Buxl-Future (30 year) | Brent Crude Oil | WTI Crude Oil | Heating Oil | Natural Gas | Gold | Silver | Platinum | Palladium | Copper | Nickel | Zinc | Lean hogs | Live cattle | Feeder cattle | Wheat | Corn | Oat | Soybeans | Soybean oil | Frozen orange juice | Cocoa | Coffee | Sugar No.11 | Cotton No.2 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Date | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 1999-12-02 | -0.004590 | -0.006265 | 0.000000 | -4.709523e-04 | -0.005719 | -4.507896e-03 | -0.004931 | -0.006932 | 0.032159 | 0.006189 | 0.001339 | -0.000488 | -0.001752 | -0.005761 | -0.009062 | -0.001177 | -0.008317 | -0.007219 | -0.000413 | -0.000919 | -0.001871 | -0.005999 | 0.001356 | 0.002393 | 0.008732 | 0.008788 | 0.038264 | 0.032342 | 0.032365 | -0.028020 | -0.016580 | -0.016017 | 0.005473 | 0.012976 | -0.008719 | 0.011721 | -0.012531 | 0.001436 | -0.004316 | -0.000593 | 0.017043 | 0.001234 | 6.706804e-03 | 0.006853 | 0.016702 | -0.009761 | -0.023300 | -0.038236 | -0.001726 | -0.003552 |
| 1999-12-03 | -0.004692 | -0.006566 | -0.000616 | -1.544988e-17 | -0.006513 | -3.003005e-03 | -0.002384 | -0.024825 | 0.012592 | -0.011404 | -0.012007 | -0.025189 | -0.009509 | 0.011870 | -0.022211 | 0.018092 | -0.006757 | -0.026087 | 0.001191 | 0.002866 | 0.002934 | -0.009766 | 0.002422 | 0.005073 | 0.011830 | 0.015687 | 0.038733 | 0.032756 | 0.035975 | 0.026250 | -0.034136 | -0.014052 | 0.008097 | 0.007108 | 0.008030 | -0.020068 | 0.006418 | 0.008575 | -0.005046 | 0.004728 | -0.001325 | 0.006184 | 4.482837e-03 | 0.006326 | 0.007017 | -0.013333 | -0.037545 | -0.096109 | 0.037425 | -0.017286 |
| 1999-12-06 | 0.009850 | 0.013086 | -0.004212 | -1.130333e-02 | 0.000952 | 4.553649e-17 | -0.019724 | -0.016267 | 0.003031 | -0.022353 | -0.019377 | -0.049985 | -0.012402 | -0.017542 | -0.022211 | -0.015915 | -0.008525 | -0.044097 | 0.000871 | 0.002408 | 0.001337 | 0.006353 | 0.001548 | 0.002577 | 0.039004 | 0.003218 | 0.005489 | 0.000413 | 0.017507 | -0.020740 | -0.048068 | -0.012092 | 0.005938 | -0.013687 | 0.005578 | -0.028011 | -0.006301 | 0.013323 | -0.006482 | 0.009159 | 0.019063 | 0.020963 | -8.763051e-03 | 0.014755 | -0.000284 | -0.008739 | -0.023300 | -0.027884 | -0.003538 | -0.020496 |
| 1999-12-07 | 0.007571 | 0.010837 | 0.002352 | -1.462317e-02 | 0.001265 | 4.553649e-17 | -0.021122 | -0.023128 | 0.000847 | -0.025613 | -0.015115 | -0.050992 | -0.007651 | -0.021584 | -0.059892 | -0.014511 | 0.003030 | -0.040656 | 0.000367 | 0.000465 | -0.001848 | -0.002468 | 0.001936 | 0.002194 | 0.037608 | -0.000341 | 0.021050 | 0.016962 | 0.040529 | 0.000172 | -0.022519 | -0.019384 | 0.007130 | -0.007955 | 0.021032 | 0.010709 | 0.009411 | 0.006139 | -0.004685 | 0.012411 | 0.027169 | 0.027094 | -4.363900e-03 | 0.006919 | 0.010060 | -0.015412 | -0.053486 | -0.034970 | 0.022492 | -0.005927 |
| 1999-12-08 | 0.005983 | 0.008210 | 0.007783 | -1.674210e-02 | 0.000627 | 3.003005e-03 | -0.023154 | -0.030393 | 0.015432 | -0.012388 | -0.010456 | -0.050758 | -0.010844 | -0.021681 | -0.059892 | -0.020820 | 0.021592 | -0.030574 | 0.000962 | 0.001950 | -0.000522 | -0.003087 | 0.002519 | 0.003632 | 0.035355 | 0.002539 | 0.032516 | 0.028897 | 0.052935 | 0.007631 | -0.017950 | -0.014048 | 0.006882 | -0.010890 | 0.017285 | 0.016388 | 0.004267 | 0.003261 | -0.012937 | 0.004774 | 0.010758 | 0.010975 | 6.706804e-03 | 0.024243 | 0.019809 | -0.026812 | -0.046600 | -0.069233 | 0.015926 | 0.001831 |
| 1999-12-09 | 0.009356 | 0.014454 | 0.012088 | -1.462317e-02 | 0.004753 | 6.006011e-03 | -0.017066 | -0.026847 | 0.016221 | -0.012726 | -0.002706 | -0.044052 | -0.015557 | -0.024734 | -0.058859 | -0.020079 | 0.016556 | -0.000162 | 0.001420 | 0.002979 | -0.002113 | -0.006748 | 0.003490 | 0.006316 | 0.037654 | 0.000167 | 0.057448 | 0.043685 | 0.076048 | 0.008944 | -0.004486 | -0.016418 | 0.014326 | -0.008198 | 0.022905 | 0.022158 | 0.010696 | -0.007880 | -0.007206 | 0.008001 | 0.006613 | -0.002871 | 4.477880e-03 | -0.002599 | -0.011860 | -0.019029 | -0.067116 | -0.123752 | 0.027484 | -0.001770 |
| 1999-12-10 | 0.002550 | 0.005304 | 0.011369 | -1.707879e-02 | -0.001956 | 7.506386e-03 | -0.026508 | -0.022420 | 0.028614 | 0.005038 | -0.009485 | -0.054529 | -0.031618 | -0.004523 | -0.038236 | 0.002552 | 0.019702 | 0.001786 | 0.000551 | 0.000469 | -0.006872 | -0.011626 | 0.002520 | 0.003735 | 0.038993 | -0.007420 | 0.033316 | 0.007952 | 0.047330 | -0.059145 | -0.001993 | -0.014048 | 0.025361 | 0.015647 | 0.032905 | 0.031078 | 0.019065 | -0.017170 | -0.020953 | -0.002032 | 0.010758 | 0.002186 | 4.477880e-03 | 0.000660 | -0.013120 | 0.000815 | -0.054857 | -0.085633 | 0.039043 | -0.000767 |
| 1999-12-13 | 0.003247 | 0.007164 | 0.020076 | -1.502097e-02 | -0.002272 | 6.003756e-03 | -0.025259 | -0.022594 | 0.018223 | 0.000439 | -0.006253 | -0.052908 | -0.033603 | 0.003016 | -0.034402 | 0.006745 | 0.004316 | 0.005495 | 0.001191 | 0.001609 | -0.005288 | -0.010874 | 0.003296 | 0.006029 | 0.031642 | -0.001524 | 0.038094 | 0.013857 | 0.070162 | -0.084575 | 0.001929 | -0.013637 | 0.012346 | -0.000828 | 0.039787 | 0.026292 | 0.021829 | -0.024420 | -0.024607 | -0.003220 | -0.005927 | -0.010504 | -9.006133e-03 | -0.021269 | -0.027784 | -0.015133 | -0.095889 | -0.064546 | 0.037394 | 0.000433 |
| 1999-12-14 | -0.003546 | -0.001295 | 0.016717 | -7.298923e-03 | -0.002905 | 4.498865e-03 | -0.033100 | -0.014733 | 0.038170 | 0.009319 | 0.001758 | -0.044365 | -0.038389 | 0.002205 | -0.038022 | 0.008208 | 0.001065 | -0.003490 | -0.001053 | -0.002965 | 0.002667 | 0.000936 | 0.002228 | 0.003921 | 0.021158 | -0.013592 | 0.063042 | 0.027639 | 0.049632 | -0.114417 | 0.002297 | -0.026523 | 0.014227 | -0.014043 | 0.031090 | 0.029948 | 0.013784 | -0.005063 | -0.021318 | -0.003220 | 0.008688 | 0.005962 | 6.245005e-17 | -0.016844 | -0.021370 | -0.030251 | -0.092088 | -0.079535 | 0.013829 | -0.001963 |
| 1999-12-15 | -0.003743 | 0.000087 | 0.014676 | -1.178639e-02 | 0.002967 | 2.991706e-03 | -0.031529 | -0.012281 | 0.054018 | 0.015658 | -0.011728 | -0.045104 | -0.043257 | 0.012763 | -0.049212 | 0.001303 | -0.002968 | -0.032229 | -0.001832 | -0.004571 | -0.000265 | -0.000393 | 0.003005 | 0.006220 | 0.024807 | -0.006775 | 0.044617 | 0.003462 | 0.029514 | -0.075366 | -0.006888 | -0.025608 | 0.032305 | -0.014272 | -0.006537 | 0.007926 | 0.004553 | -0.013499 | -0.023144 | -0.002923 | 0.008688 | 0.005962 | 1.581952e-02 | -0.017399 | -0.021370 | -0.047817 | -0.080304 | -0.032885 | -0.010305 | 0.006451 |
| 1999-12-16 | 0.003247 | 0.009515 | 0.020383 | -8.301831e-03 | -0.002871 | 7.506386e-03 | -0.023856 | -0.006352 | 0.022021 | 0.006992 | -0.004254 | -0.071744 | -0.029617 | 0.024291 | -0.035879 | 0.016265 | 0.003697 | -0.039533 | -0.003026 | -0.006754 | -0.005083 | -0.011676 | 0.006505 | 0.014097 | 0.019125 | 0.014856 | 0.020715 | -0.014195 | 0.008190 | -0.016778 | -0.004080 | -0.030377 | 0.036849 | -0.033812 | -0.007725 | -0.000286 | -0.013661 | -0.006407 | -0.021318 | -0.003220 | -0.001622 | 0.000950 | -2.542851e-04 | -0.020717 | -0.032292 | -0.026994 | -0.088239 | -0.052176 | -0.008474 | -0.010386 |
| 1999-12-17 | 0.009357 | 0.018053 | 0.021704 | -4.548727e-03 | 0.001859 | 9.009016e-03 | -0.014297 | -0.011210 | 0.012751 | -0.001924 | -0.010859 | -0.074010 | -0.028503 | 0.028539 | -0.044342 | 0.011583 | 0.003331 | -0.019253 | -0.003209 | -0.007215 | -0.005352 | -0.014513 | 0.006700 | 0.013229 | 0.008896 | 0.009462 | 0.018045 | -0.010808 | 0.003128 | -0.023961 | -0.010033 | -0.032601 | 0.021697 | -0.043099 | -0.013064 | 0.002159 | -0.004593 | -0.009087 | -0.021683 | -0.005600 | -0.011826 | -0.006522 | 4.368376e-03 | -0.018503 | -0.034867 | -0.011694 | -0.066146 | -0.063952 | 0.013829 | -0.004877 |
| 1999-12-20 | 0.012802 | 0.021496 | 0.014812 | -3.944599e-03 | 0.004698 | 9.009016e-03 | -0.008339 | -0.004789 | 0.003129 | -0.003784 | -0.011425 | -0.072638 | -0.031982 | 0.024880 | -0.050303 | 0.005258 | -0.001491 | -0.035429 | -0.003807 | -0.009404 | -0.009386 | -0.015275 | 0.006992 | 0.012842 | 0.007059 | 0.006491 | 0.026525 | -0.004000 | -0.001790 | -0.014119 | -0.011793 | -0.027437 | 0.020463 | -0.037675 | -0.014834 | 0.009526 | -0.011234 | -0.015358 | -0.024232 | -0.005898 | -0.022932 | -0.015170 | 4.368376e-03 | -0.032229 | -0.022024 | 0.001436 | -0.084372 | -0.085619 | 0.000310 | -0.006507 |
| 1999-12-21 | 0.013394 | 0.024448 | 0.012385 | 2.072856e-04 | 0.011822 | 1.051165e-02 | -0.005207 | 0.008704 | -0.040167 | -0.023727 | -0.013741 | -0.081123 | -0.022969 | 0.028846 | -0.041653 | 0.014546 | -0.010500 | -0.032523 | -0.004037 | -0.010096 | -0.011004 | -0.010754 | 0.007965 | 0.015542 | 0.013999 | 0.017110 | 0.026077 | -0.007018 | 0.002538 | 0.027432 | -0.021872 | -0.034058 | 0.035411 | -0.034157 | 0.001239 | 0.002973 | -0.014157 | -0.009982 | -0.029304 | 0.001819 | -0.010810 | -0.010238 | 8.964579e-03 | -0.028403 | -0.020130 | 0.007979 | -0.084372 | 0.028568 | 0.006997 | 0.000803 |
| 1999-12-22 | 0.013197 | 0.024647 | 0.008464 | 2.816943e-03 | 0.014685 | 1.201428e-02 | -0.005991 | 0.006643 | -0.045847 | -0.023696 | -0.010129 | -0.089427 | -0.023603 | 0.011210 | -0.040036 | 0.034977 | -0.031839 | -0.030925 | -0.004220 | -0.010443 | -0.011544 | 0.000272 | 0.008744 | 0.016602 | 0.018457 | 0.019190 | 0.000184 | -0.036468 | 0.019620 | -0.003984 | -0.021191 | -0.021263 | 0.011291 | -0.029728 | 0.025549 | 0.029177 | 0.003654 | -0.005505 | -0.028942 | 0.001523 | -0.002713 | -0.004076 | 8.964579e-03 | -0.050597 | -0.044740 | -0.000262 | -0.104911 | 0.002974 | 0.012142 | 0.002827 |
| 1999-12-23 | 0.007768 | 0.030245 | 0.009666 | 6.895715e-03 | 0.013263 | 1.801130e-02 | -0.002701 | -0.009017 | -0.052594 | -0.039131 | 0.002489 | -0.141858 | -0.005781 | -0.014162 | -0.022788 | 0.007065 | -0.031839 | -0.038302 | -0.004312 | -0.011136 | -0.012625 | 0.006355 | 0.008938 | 0.017180 | 0.026330 | 0.016418 | 0.022033 | -0.022044 | 0.027543 | -0.022568 | -0.020490 | -0.017422 | 0.019975 | -0.035712 | 0.026719 | 0.029418 | 0.001601 | -0.003265 | -0.033269 | -0.004069 | -0.009745 | -0.007755 | 6.674376e-03 | -0.050597 | -0.047829 | 0.000845 | -0.055744 | 0.033114 | 0.010454 | -0.005448 |
| 1999-12-24 | 0.010043 | 0.030245 | 0.009666 | 6.895715e-03 | 0.013263 | 1.801130e-02 | -0.002701 | -0.009017 | -0.052594 | -0.044463 | -0.002195 | -0.141858 | -0.005781 | -0.028648 | -0.022788 | 0.007065 | -0.028230 | -0.071897 | -0.004312 | -0.011136 | -0.012625 | 0.005969 | 0.008938 | 0.017180 | 0.026330 | 0.016418 | 0.021132 | -0.022044 | 0.027543 | -0.022568 | -0.020490 | -0.017422 | 0.019975 | -0.035712 | 0.026719 | 0.013943 | 0.010866 | -0.003265 | -0.033269 | -0.004069 | -0.009745 | -0.007755 | 6.674376e-03 | -0.050597 | -0.047829 | 0.000845 | -0.055744 | 0.033114 | 0.010454 | -0.005448 |
| 1999-12-27 | 0.010439 | 0.032303 | 0.015417 | 4.895848e-03 | 0.017220 | 1.056524e-02 | 0.000276 | -0.007156 | -0.051494 | -0.044463 | -0.002195 | -0.150516 | -0.003869 | -0.024018 | -0.017442 | 0.000902 | -0.032420 | -0.071897 | -0.003761 | -0.010443 | -0.011814 | 0.005969 | 0.008160 | 0.016410 | 0.026156 | 0.015207 | 0.021132 | -0.039686 | 0.009599 | -0.065200 | -0.024990 | -0.015904 | 0.024701 | -0.046795 | 0.027891 | 0.013849 | 0.011155 | -0.003265 | -0.032547 | -0.000838 | 0.001327 | -0.006530 | 6.674376e-03 | -0.032229 | -0.030279 | -0.013584 | -0.064175 | 0.025719 | 0.017286 | 0.012402 |
| 1999-12-28 | 0.013989 | 0.025512 | 0.014708 | 6.295335e-03 | 0.011801 | 3.174228e-03 | -0.007295 | -0.007831 | -0.046676 | -0.044463 | -0.002195 | -0.140307 | -0.002417 | -0.017053 | -0.000538 | 0.012045 | -0.041856 | -0.079239 | -0.003301 | -0.009172 | -0.009651 | 0.005969 | 0.009133 | 0.019109 | 0.038173 | 0.021448 | 0.021132 | -0.058207 | -0.005207 | -0.033901 | -0.030839 | -0.013474 | 0.038353 | -0.047250 | 0.027305 | 0.013849 | 0.011155 | 0.018918 | -0.032547 | -0.000544 | 0.002339 | -0.010200 | 8.964579e-03 | -0.032777 | -0.034621 | -0.010797 | -0.041533 | 0.051845 | 0.017286 | 0.013629 |
| 1999-12-29 | 0.013688 | 0.024420 | 0.016528 | 8.160883e-03 | 0.008762 | 7.602279e-03 | -0.008560 | -0.010195 | -0.013552 | -0.056279 | -0.007766 | -0.142379 | -0.006689 | -0.016836 | 0.004718 | 0.020260 | -0.042020 | -0.059907 | -0.002657 | -0.008132 | -0.008028 | 0.004279 | 0.009328 | 0.019012 | 0.036609 | 0.021275 | 0.011730 | -0.045099 | 0.000341 | -0.044399 | -0.033929 | 0.018943 | 0.031140 | -0.059410 | 0.019710 | 0.017879 | 0.030319 | 0.009254 | -0.033269 | -0.002303 | 0.000315 | -0.005304 | 1.125478e-02 | -0.040304 | -0.043984 | -0.001914 | -0.032036 | 0.060213 | -0.019145 | 0.027636 |
window
20
# Function to calculate rebalanced weights based on 12-day volatility
def calculate_rebalanced_weights_volatility(df, window):
# Calculate rolling standard deviation for each asset
rolling_vol = df.diff().rolling(window=window).std().fillna(0)
small_constant = 1e-8 # Small constant to avoid division by zero
# Calculate inverse volatility, avoiding division by zero by adding small constant
# Only consider non-zero volatilities in the weight calculation
inverse_volatility = 1 / (rolling_vol + small_constant)
inverse_volatility[rolling_vol == 0] = 0 # Set inverse volatility to zero where rolling volatility is zero
# Sum of inverse volatilities (excluding those set to zero)
sum_inverse_volatility = inverse_volatility.sum(axis=1)
# Initialize daily weights DataFrame
daily_weights = pd.DataFrame(index=df.index, columns=df.columns)
# Assign weights daily based on non-zero inverse volatility
for day in range(len(daily_weights)):
daily_weights.iloc[day] = inverse_volatility.iloc[day] / sum_inverse_volatility.iloc[day]
return daily_weights
# Ensure the DataFrame index is in datetime format
combined_df_kalman_cleaned_vol.index = pd.to_datetime(combined_df_kalman_cleaned_vol.index)
# Calculate daily rebalanced weights based on volatility using the full dataset
weights_kalman_vol = calculate_rebalanced_weights_volatility(combined_df_kalman_cleaned_vol, window)
# Starting calculation from the start date
#start_date = '2000-01-01'
# Filter the weights and returns dataframes from the start date
weights_kalman_vol_from_start = weights_kalman_vol[weights_kalman_vol.index >= start_date]
daily_log_returns_kalman_vol = combined_df_kalman_cleaned_vol.diff().fillna(0)[combined_df_kalman_cleaned_vol.index >= start_date]
# Calculate portfolio log returns using the new weights
portfolio_kalman_log_returns_vol = (daily_log_returns_kalman_vol * weights_kalman_vol_from_start).sum(axis=1)
portfolio_kalman_simple_returns_vol = np.exp(portfolio_kalman_log_returns_vol) - 1
portfolio_kalman_cumulative_simple_returns_vol = (1 + portfolio_kalman_simple_returns_vol).cumprod() - 1
# Plot the performance
trace = go.Scatter(x=weights_kalman_vol_from_start.index, y=portfolio_kalman_cumulative_simple_returns_vol, mode='lines', name='Cumulative Simple Returns with Daily Rebalancing')
data = [trace]
layout = go.Layout(title='Inverse Volatility Weighted Portfolio Kalman with Daily Rebalancing - from 2000', xaxis=dict(title='Days'), yaxis=dict(title='Simple Return'))
fig = go.Figure(data=data, layout=layout)
fig.show()
# Save the weights to an Excel file
weights_kalman_vol_from_start.to_excel('rebalanced_weights_volatility_kalman.xlsx')
<ipython-input-92-9d68be3fe576>:48: UserWarning: Pandas requires version '1.4.3' or newer of 'xlsxwriter' (version '1.3.8' currently installed).
SPY = qs.utils.download_returns('SPY')
SPY_df = pd.DataFrame(SPY)
SPY_df.index = pd.to_datetime(SPY_df.index)
SPY_df_filterd = SPY_df['2000-01-05':'2023-12-31']
SPY = SPY_df_filterd['Close']
SPY['Cumulative_simple_return'] = (1 + SPY).cumprod() - 1
[*********************100%***********************] 1 of 1 completed
<ipython-input-93-99472245db3f>:6: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
# Creating the trace for the current feature
trace = go.Scatter(x=SPY.index, y=SPY['Cumulative_simple_return'], mode='lines', name='Simple return')
# Creating the data list with the current trace
data = [trace]
# Creating the layout for the current plot, dynamically setting the title to the current feature
layout = go.Layout(title='SPY - over Time', yaxis=dict(title='Simple return'))
# Creating the figure with the current data and layout
fig = go.Figure(data=data, layout=layout)
# Displaying the figure
fig.show()
BarclayHedgeCTA = pd.read_excel('BarclayHedge CTA Index.xlsx', index_col = 'Date', parse_dates = True)
BarclayHedgeCTA['Simple_returns'] = BarclayHedgeCTA['Price'] / BarclayHedgeCTA['Price'].shift(1) - 1
BarclayHedgeCTA['Log_Returns'] = np.log(BarclayHedgeCTA['Price'] / BarclayHedgeCTA['Price'].shift(1))
BarclayHedgeCTA_filtered = BarclayHedgeCTA.loc[strategy_start:]
BarclayHedgeCTA_filtered['Cumulative_Log_Returns'] = BarclayHedgeCTA_filtered['Log_Returns'].cumsum()
BarclayHedgeCTA_filtered['Cumulative_simple_return'] = (1 + BarclayHedgeCTA_filtered['Simple_returns']).cumprod() - 1
BarclayHedgeCTA_filtered.head(10)
<ipython-input-95-2ae0cf60a41d>:6: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy <ipython-input-95-2ae0cf60a41d>:7: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
| Price | Simple_returns | Log_Returns | Cumulative_Log_Returns | Cumulative_simple_return | |
|---|---|---|---|---|---|
| Date | |||||
| 2000-01-31 | 16264.63 | 0.014100 | 0.014002 | 0.014002 | 0.014100 |
| 2000-02-29 | 16193.06 | -0.004400 | -0.004410 | 0.009592 | 0.009638 |
| 2000-03-31 | 16058.66 | -0.008300 | -0.008334 | 0.001257 | 0.001258 |
| 2000-04-30 | 15800.11 | -0.016100 | -0.016231 | -0.014974 | -0.014862 |
| 2000-05-31 | 15926.51 | 0.008000 | 0.007968 | -0.007006 | -0.006981 |
| 2000-06-30 | 15775.21 | -0.009500 | -0.009545 | -0.016551 | -0.016415 |
| 2000-07-31 | 15585.91 | -0.012000 | -0.012072 | -0.028624 | -0.028218 |
| 2000-08-31 | 15984.91 | 0.025600 | 0.025278 | -0.003346 | -0.003340 |
| 2000-09-30 | 15746.73 | -0.014900 | -0.015012 | -0.018358 | -0.018191 |
| 2000-10-31 | 15885.31 | 0.008801 | 0.008762 | -0.009596 | -0.009550 |
what_to_plot = 'BarclayHedgeCTA'
# Creating the trace for the current feature
trace = go.Scatter(x=BarclayHedgeCTA.index, y=BarclayHedgeCTA_filtered['Cumulative_simple_return'], mode='lines', name='Simple return Price')
# Creating the data list with the current trace
data = [trace]
# Creating the layout for the current plot, dynamically setting the title to the current feature
layout = go.Layout(title='BarclayHedge CTA Index - over Time', xaxis=dict(title='Days'), yaxis=dict(title='Simple return'))
# Creating the figure with the current data and layout
fig = go.Figure(data=data, layout=layout)
# Displaying the figure
fig.show()
# Line SPY
trace_SPY = go.Scatter(
x=SPY.index,
y=SPY['Cumulative_simple_return'],
mode='lines',
name='SPY'
)
# Line BarclayHedge
trace_BarclayHedge = go.Scatter(
x=BarclayHedgeCTA_filtered.index,
y=BarclayHedgeCTA_filtered['Cumulative_simple_return'],
mode='lines',
name='BarclayHedgeCTA Index'
)
# Line SMA
trace_SMA = go.Scatter(
x=combined_df_SMA_cleaned.index,
y=portfolio_SMA_cumulative_simple_returns,
mode='lines',
name='SMA EW'
)
# Line SMA with Bands
trace_SMA_bands = go.Scatter(
x=combined_df_SMA_bands_cleaned.index,
y=portfolio_SMA_bands_cumulative_simple_returns,
mode='lines',
name='SMA with Bands EW'
)
# Line TSMOM
trace_TSMOM = go.Scatter(
x=combined_df_TSMOM_cleaned.index,
y=portfolio_TSMOM_cumulative_simple_returns,
mode='lines',
name='TSMOM EW'
)
# Line RAMOM
trace_RAMOM = go.Scatter(
x=combined_df_RAMOM_cleaned.index,
y=portfolio_RAMOM_cumulative_simple_returns,
mode='lines',
name='RAMOM EW'
)
# Line Kalman
trace_kalman = go.Scatter(
x=combined_df_kalman_cleaned.index,
y=portfolio_kalman_cumulative_simple_returns,
mode='lines',
name='Kalman Filter EW'
)
# Combine all traces
data = [trace_SPY, trace_BarclayHedge, trace_SMA, trace_SMA_bands, trace_TSMOM, trace_RAMOM, trace_kalman]
# Define layout
layout = go.Layout(
title={
'text': 'All equal weighted portfolios over time',
'y': 0.9,
'x': 0.5,
'xanchor': 'center',
'yanchor': 'top',
'font': dict(size=18, color='black', family='Arial'),
},
plot_bgcolor='white',
paper_bgcolor='white',
xaxis=dict(
showgrid=True,
gridcolor='lightgrey',
tickangle=-45 # Rotate the x-axis labels by 45 degrees
),
yaxis=dict(
title='Simple Return',
showgrid=True,
gridcolor='lightgrey'
)
)
# Create figure and add data and layout
fig = go.Figure(data=data, layout=layout)
# Show the figure
fig.show()
# Simple Return Data for the EW:
return_data = [portfolio_SMA_simple_returns,
portfolio_SMA_bands_simple_returns,
portfolio_TSMOM_simple_returns,
portfolio_RAMOM_simple_returns,
portfolio_kalman_simple_returns
]
# Making it possible to use it as Benchmark
BarclayHedgeCTA = BarclayHedgeCTA_filtered['Simple_returns']
BarclayHedgeCTA_df = pd.DataFrame(BarclayHedgeCTA)
BarclayHedgeCTA_df.columns = ['BarclayHedgeCTA']
qs.plots.snapshot(BarclayHedgeCTA, title='BarclayHedgeCTA', show=True)
qs.plots.snapshot(portfolio_SMA_simple_returns, title='SMA EW', show=True)
qs.reports.html(portfolio_SMA_simple_returns, BarclayHedgeCTA_df['BarclayHedgeCTA'], title='SMA Strategy Tearsheet EW', download_filename='SMA Strategy Tearsheet EW.html')
C:\Users\Raphael\anaconda3\lib\site-packages\seaborn\categorical.py:82: FutureWarning: iteritems is deprecated and will be removed in a future version. Use .items instead.
qs.plots.snapshot(portfolio_SMA_bands_simple_returns, title='SMA with Bands EW', show=True)
qs.reports.html(portfolio_SMA_bands_simple_returns, BarclayHedgeCTA_df['BarclayHedgeCTA'], title='SMA with Bands Strategy Tearsheet EW', download_filename='SMA with Bands Strategy Tearsheet EW.html')
C:\Users\Raphael\anaconda3\lib\site-packages\seaborn\categorical.py:82: FutureWarning: iteritems is deprecated and will be removed in a future version. Use .items instead.
qs.plots.snapshot(portfolio_TSMOM_simple_returns, title='TSMOM EW', show=True)
qs.reports.html(portfolio_TSMOM_simple_returns, BarclayHedgeCTA_df['BarclayHedgeCTA'], title='TSMOM Strategy Tearsheet EW', download_filename='TSMOM Strategy Tearsheet EW.html')
C:\Users\Raphael\anaconda3\lib\site-packages\seaborn\categorical.py:82: FutureWarning: iteritems is deprecated and will be removed in a future version. Use .items instead.
qs.plots.snapshot(portfolio_RAMOM_simple_returns, title='RAMOM EW', show=True)
qs.reports.html(portfolio_RAMOM_simple_returns, BarclayHedgeCTA_df['BarclayHedgeCTA'], title='RAMOM Strategy Tearsheet EW', download_filename='RAMOM Strategy Tearsheet EW.html')
C:\Users\Raphael\anaconda3\lib\site-packages\seaborn\categorical.py:82: FutureWarning: iteritems is deprecated and will be removed in a future version. Use .items instead.
qs.plots.snapshot(portfolio_kalman_simple_returns, title='Kalman EW', show=True)
qs.reports.html(portfolio_kalman_simple_returns, BarclayHedgeCTA_df['BarclayHedgeCTA'], title='Kalman Strategy Tearsheet EW', download_filename='Kalman Strategy Tearsheet EW.html')
C:\Users\Raphael\anaconda3\lib\site-packages\seaborn\categorical.py:82: FutureWarning: iteritems is deprecated and will be removed in a future version. Use .items instead.
# Line SPY
trace_SPY = go.Scatter(
x=SPY.index,
y=SPY['Cumulative_simple_return'],
mode='lines',
name='SPY'
)
# Line BarclayHedge
trace_BarclayHedge = go.Scatter(
x=BarclayHedgeCTA_filtered.index,
y=BarclayHedgeCTA_filtered['Cumulative_simple_return'],
mode='lines',
name='BarclayHedgeCTA Index'
)
# Line SMA
trace_SMA = go.Scatter(
x=combined_df_SMA_cleaned.index,
y=portfolio_SMA_cumulative_simple_returns_vol,
mode='lines',
name='SMA VW'
)
# Line SMA with Bands
trace_SMA_bands = go.Scatter(
x=combined_df_SMA_bands_cleaned.index,
y=portfolio_SMA_bands_cumulative_simple_returns_vol,
mode='lines',
name='SMA with Bands VW'
)
# Line TSMOM
trace_TSMOM = go.Scatter(
x=combined_df_TSMOM_cleaned.index,
y=portfolio_TSMOM_cumulative_simple_returns_vol,
mode='lines',
name='TSMOM VW'
)
# Line RAMOM
trace_RAMOM = go.Scatter(
x=combined_df_RAMOM_cleaned.index,
y=portfolio_RAMOM_cumulative_simple_returns_vol,
mode='lines',
name='RAMOM VW'
)
# Line Kalman
trace_kalman = go.Scatter(
x=combined_df_kalman_cleaned.index,
y=portfolio_kalman_cumulative_simple_returns_vol,
mode='lines',
name='Kalman Filter VW'
)
# Combine all traces
data = [trace_SPY, trace_BarclayHedge, trace_SMA, trace_SMA_bands, trace_TSMOM, trace_RAMOM, trace_kalman]
# Define layout
layout = go.Layout(
title={
'text': 'All volatility weighted portfolios over time',
'y': 0.9,
'x': 0.5,
'xanchor': 'center',
'yanchor': 'top',
'font': dict(size=18, color='black', family='Arial'),
},
plot_bgcolor='white',
paper_bgcolor='white',
xaxis=dict(
showgrid=True,
gridcolor='lightgrey',
tickangle=-45 # Rotate the x-axis labels by 45 degrees
),
yaxis=dict(
title='Simple Return',
showgrid=True,
gridcolor='lightgrey'
)
)
# Create figure and add data and layout
fig = go.Figure(data=data, layout=layout)
# Show the figure
fig.show()
# Simple Return Data for VW
return_data_vol = [portfolio_SMA_simple_returns_vol,
portfolio_SMA_bands_simple_returns_vol,
portfolio_TSMOM_simple_returns_vol,
portfolio_RAMOM_simple_returns_vol,
portfolio_kalman_simple_returns_vol
]
qs.plots.snapshot(BarclayHedgeCTA, title='BarclayHedgeCTA', show=True)
qs.plots.snapshot(portfolio_SMA_simple_returns_vol, title='SMA VW', show=True)
qs.reports.html(portfolio_SMA_simple_returns_vol, BarclayHedgeCTA_df['BarclayHedgeCTA'], title='SMA Strategy Tearsheet VW', download_filename='SMA Strategy Tearsheet VW.html')
C:\Users\Raphael\anaconda3\lib\site-packages\seaborn\categorical.py:82: FutureWarning: iteritems is deprecated and will be removed in a future version. Use .items instead.
qs.plots.snapshot(portfolio_SMA_bands_simple_returns_vol, title='SMA with Bands VW', show=True)
qs.reports.html(portfolio_SMA_bands_simple_returns_vol, BarclayHedgeCTA_df['BarclayHedgeCTA'], title='SMA with Bands Strategy Tearsheet VW', download_filename='SMA with Bands Strategy Tearsheet VW.html')
C:\Users\Raphael\anaconda3\lib\site-packages\seaborn\categorical.py:82: FutureWarning: iteritems is deprecated and will be removed in a future version. Use .items instead.
qs.plots.snapshot(portfolio_TSMOM_simple_returns_vol, title='TSMOM VW', show=True)
qs.reports.html(portfolio_TSMOM_simple_returns_vol, BarclayHedgeCTA_df['BarclayHedgeCTA'], title='TSMOM Strategy Tearsheet VW', download_filename='TSMOM Strategy Tearsheet VW.html')
C:\Users\Raphael\anaconda3\lib\site-packages\seaborn\categorical.py:82: FutureWarning: iteritems is deprecated and will be removed in a future version. Use .items instead.
qs.plots.snapshot(portfolio_RAMOM_simple_returns_vol, title='RAMOM VW', show=True)
qs.reports.html(portfolio_RAMOM_simple_returns_vol, BarclayHedgeCTA_df['BarclayHedgeCTA'], title='RAMOM Strategy Tearsheet VW', download_filename='RAMOM Strategy Tearsheet VW.html')
C:\Users\Raphael\anaconda3\lib\site-packages\seaborn\categorical.py:82: FutureWarning: iteritems is deprecated and will be removed in a future version. Use .items instead.
qs.plots.snapshot(portfolio_kalman_simple_returns_vol, title='Kalman VW', show=True)
qs.reports.html(portfolio_kalman_simple_returns_vol, BarclayHedgeCTA_df['BarclayHedgeCTA'], title='Kalman Strategy Tearsheet VW', download_filename='Kalman Strategy Tearsheet VW.html')
C:\Users\Raphael\anaconda3\lib\site-packages\seaborn\categorical.py:82: FutureWarning: iteritems is deprecated and will be removed in a future version. Use .items instead.
SPY = qs.utils.download_returns('SPY')
SPY_df = pd.DataFrame(SPY)
SPY_df.index = pd.to_datetime(SPY_df.index)
SPY_df_filterd = SPY_df['2000-01-05':'2023-12-31']
SPY = SPY_df_filterd['Close']
[*********************100%***********************] 1 of 1 completed
# Assuming each strategy variable is already defined and holds return data
strategies = {
"SPY": SPY,
"BarclayHedgeCTA": BarclayHedgeCTA,
"SMA EW": portfolio_SMA_simple_returns,
"SMA with Bands EW": portfolio_SMA_bands_simple_returns,
"TSMOM EW": portfolio_TSMOM_simple_returns,
"RAMOM EW": portfolio_RAMOM_simple_returns,
"Kalman EW": portfolio_kalman_simple_returns,
"SMA VW": portfolio_SMA_simple_returns_vol,
"SMA with Bands VW": portfolio_SMA_bands_simple_returns_vol,
"TSMOM VW": portfolio_TSMOM_simple_returns_vol,
"RAMOM VW": portfolio_RAMOM_simple_returns_vol,
"Kalman VW": portfolio_kalman_simple_returns_vol
}
# Create a DataFrame to store the results
results = pd.DataFrame()
# Calculate metrics for each strategy
for name, data in strategies.items():
if name == "BarclayHedgeCTA":
# Special calculations for BarclayHedgeCTA
results.loc[name, 'Total Return'] = qs.stats.comp(data)
results.loc[name, 'Annualized Volatility'] = qs.stats.volatility(data, periods=12)
results.loc[name, 'Sharpe Ratio'] = qs.stats.sharpe(data, periods=12)
results.loc[name, 'Max Drawdown'] = qs.stats.max_drawdown(data)
results.loc[name, 'Sortino Ratio'] = qs.stats.sortino(data, periods=12)
results.loc[name, 'Beta SPY'] = qs.stats.greeks(data, benchmark=SPY)['beta']
else:
# General calculations for all other strategies
results.loc[name, 'Total Return'] = qs.stats.comp(data)
results.loc[name, 'Annualized Volatility'] = qs.stats.volatility(data)
results.loc[name, 'Sharpe Ratio'] = qs.stats.sharpe(data)
results.loc[name, 'Max Drawdown'] = qs.stats.max_drawdown(data)
results.loc[name, 'Sortino Ratio'] = qs.stats.sortino(data)
if name != 'SPY': # Assuming you don't want to calculate beta for SPY against itself
greek = qs.stats.greeks(data, benchmark=SPY)
results.loc[name, 'Beta SPY'] = greek['beta']
if name != 'BarclayHedgeCTA': # Assuming you don't want to calculate beta for SPY against itself
greek = qs.stats.greeks(data, benchmark=BarclayHedgeCTA)
results.loc[name, 'Beta CTA'] = greek['beta']
# Save results to Excel
results.to_excel('Results_Overall.xlsx')
# Display the results DataFrame
results
<ipython-input-114-512920e91555>:45: UserWarning: Pandas requires version '1.4.3' or newer of 'xlsxwriter' (version '1.3.8' currently installed).
| Total Return | Annualized Volatility | Sharpe Ratio | Max Drawdown | Sortino Ratio | Beta CTA | Beta SPY | |
|---|---|---|---|---|---|---|---|
| SPY | 2.401145 | 0.196481 | 0.358477 | -0.564737 | 0.504624 | 0.030341 | NaN |
| BarclayHedgeCTA | 1.260104 | 0.058528 | 0.610281 | -0.099127 | 1.068440 | NaN | -0.034969 |
| SMA EW | 1.395916 | 0.084803 | 0.457838 | -0.223292 | 0.689000 | 0.013432 | -0.115380 |
| SMA with Bands EW | 1.373744 | 0.084273 | 0.455734 | -0.225821 | 0.686411 | 0.014396 | -0.114715 |
| TSMOM EW | 1.016600 | 0.082845 | 0.382761 | -0.268425 | 0.563773 | 0.025145 | -0.091794 |
| RAMOM EW | 0.454955 | 0.081090 | 0.226812 | -0.348309 | 0.339012 | 0.004948 | -0.068733 |
| Kalman EW | -0.442506 | 0.072751 | -0.287592 | -0.469481 | -0.394614 | -0.000488 | 0.047530 |
| SMA VW | 1.057769 | 0.037591 | 0.793450 | -0.100159 | 1.176060 | 0.005343 | -0.054028 |
| SMA with Bands VW | 1.100254 | 0.037715 | 0.812835 | -0.097420 | 1.193871 | 0.005799 | -0.052074 |
| TSMOM VW | 1.019601 | 0.036822 | 0.788732 | -0.125532 | 1.142775 | 0.006581 | -0.047400 |
| RAMOM VW | 0.437113 | 0.035232 | 0.432955 | -0.184973 | 0.633891 | 0.006416 | -0.030480 |
| Kalman VW | -0.291648 | 0.031524 | -0.425595 | -0.316244 | -0.568984 | -0.001630 | 0.025687 |
# Assuming each strategy variable is already defined and holds return data
strategies = {
"SPY": SPY,
"BarclayHedgeCTA": BarclayHedgeCTA,
"SMA EW": portfolio_SMA_simple_returns,
"SMA with Bands EW": portfolio_SMA_bands_simple_returns,
"TSMOM EW": portfolio_TSMOM_simple_returns,
"RAMOM EW": portfolio_RAMOM_simple_returns,
"Kalman EW": portfolio_kalman_simple_returns,
"SMA VW": portfolio_SMA_simple_returns_vol,
"SMA with Bands VW": portfolio_SMA_bands_simple_returns_vol,
"TSMOM VW": portfolio_TSMOM_simple_returns_vol,
"RAMOM VW": portfolio_RAMOM_simple_returns_vol,
"Kalman VW": portfolio_kalman_simple_returns_vol
}
# Create a DataFrame to store the results
results_2000_recession = pd.DataFrame()
# Define subperiod
start_date = '2001-03-01'
end_date = '2001-11-30'
# Calculate metrics for each strategy during the subperiod
for name, data in strategies.items():
# Filter data for the subperiod
subperiod_data_2000_recession = data[start_date:end_date]
if name == "BarclayHedgeCTA":
# Special calculations for BarclayHedgeCTA
results_2000_recession.loc[name, 'Total Return'] = qs.stats.comp(subperiod_data_2000_recession)
results_2000_recession.loc[name, 'Annualized Volatility'] = qs.stats.volatility(subperiod_data_2000_recession, periods=12)
results_2000_recession.loc[name, 'Sharpe Ratio'] = qs.stats.sharpe(subperiod_data_2000_recession, periods=12)
results_2000_recession.loc[name, 'Max Drawdown'] = qs.stats.max_drawdown(subperiod_data_2000_recession)
results_2000_recession.loc[name, 'Sortino Ratio'] = qs.stats.sortino(subperiod_data_2000_recession, periods=12)
results_2000_recession.loc[name, 'Beta SPY'] = qs.stats.greeks(subperiod_data_2000_recession, benchmark=SPY[start_date:end_date])['beta']
else:
# General calculations for all other strategies
results_2000_recession.loc[name, 'Total Return'] = qs.stats.comp(subperiod_data_2000_recession)
results_2000_recession.loc[name, 'Annualized Volatility'] = qs.stats.volatility(subperiod_data_2000_recession)
results_2000_recession.loc[name, 'Sharpe Ratio'] = qs.stats.sharpe(subperiod_data_2000_recession)
results_2000_recession.loc[name, 'Max Drawdown'] = qs.stats.max_drawdown(subperiod_data_2000_recession)
results_2000_recession.loc[name, 'Sortino Ratio'] = qs.stats.sortino(subperiod_data_2000_recession)
if name != 'SPY': # Assuming you don't want to calculate beta for SPY against itself
greek = qs.stats.greeks(subperiod_data_2000_recession, benchmark=SPY[start_date:end_date])
results_2000_recession.loc[name, 'Beta SPY'] = greek['beta']
if name != 'BarclayHedgeCTA': # Assuming you don't want to calculate beta for SPY against itself
greek = qs.stats.greeks(subperiod_data_2000_recession, benchmark=BarclayHedgeCTA[start_date:end_date])
results_2000_recession.loc[name, 'Beta CTA'] = greek['beta']
# Save results to Excel (optional)
results_2000_recession.to_excel('Results_2000_recession.xlsx')
# Display the results DataFrame
results_2000_recession
<ipython-input-115-261f959634d1>:52: UserWarning: Pandas requires version '1.4.3' or newer of 'xlsxwriter' (version '1.3.8' currently installed).
| Total Return | Annualized Volatility | Sharpe Ratio | Max Drawdown | Sortino Ratio | Beta CTA | Beta SPY | |
|---|---|---|---|---|---|---|---|
| SPY | -0.079871 | 0.226033 | -0.380768 | -0.261071 | -0.514466 | -0.111787 | NaN |
| BarclayHedgeCTA | 0.004781 | 0.101166 | 0.108075 | -0.048715 | 0.156686 | NaN | -0.317347 |
| SMA EW | 0.099294 | 0.063000 | 1.953997 | -0.045024 | 3.019277 | 0.039213 | -0.147946 |
| SMA with Bands EW | 0.094613 | 0.062545 | 1.880423 | -0.043751 | 2.886882 | 0.044260 | -0.146286 |
| TSMOM EW | 0.107684 | 0.063726 | 2.085137 | -0.028989 | 3.219221 | 0.070039 | -0.144619 |
| RAMOM EW | 0.083373 | 0.064927 | 1.610360 | -0.038224 | 2.333775 | -0.027886 | -0.119238 |
| Kalman EW | -0.087078 | 0.056400 | -2.037741 | -0.105363 | -2.604322 | 0.010887 | 0.027425 |
| SMA VW | 0.050666 | 0.031475 | 2.024549 | -0.021106 | 3.251827 | 0.011611 | -0.068056 |
| SMA with Bands VW | 0.042883 | 0.028715 | 1.885025 | -0.017850 | 2.992080 | 0.013065 | -0.057638 |
| TSMOM VW | 0.055765 | 0.031301 | 2.233580 | -0.017844 | 3.634891 | 0.021920 | -0.064178 |
| RAMOM VW | 0.057343 | 0.030722 | 2.337286 | -0.014562 | 3.819972 | 0.006435 | -0.046333 |
| Kalman VW | -0.047006 | 0.027414 | -2.232705 | -0.062665 | -2.789251 | 0.002779 | 0.013199 |
# Assuming each strategy variable is already defined and holds return data
strategies = {
"SPY": SPY,
"BarclayHedgeCTA": BarclayHedgeCTA,
"SMA EW": portfolio_SMA_simple_returns,
"SMA with Bands EW": portfolio_SMA_bands_simple_returns,
"TSMOM EW": portfolio_TSMOM_simple_returns,
"RAMOM EW": portfolio_RAMOM_simple_returns,
"Kalman EW": portfolio_kalman_simple_returns,
"SMA VW": portfolio_SMA_simple_returns_vol,
"SMA with Bands VW": portfolio_SMA_bands_simple_returns_vol,
"TSMOM VW": portfolio_TSMOM_simple_returns_vol,
"RAMOM VW": portfolio_RAMOM_simple_returns_vol,
"Kalman VW": portfolio_kalman_simple_returns_vol
}
# Create a DataFrame to store the results
results_great_recession = pd.DataFrame()
# Define subperiod
start_date = '2007-12-01'
end_date = '2009-06-30'
# Calculate metrics for each strategy during the subperiod
for name, data in strategies.items():
# Filter data for the subperiod
subperiod_data_great_recession = data[start_date:end_date]
if name == "BarclayHedgeCTA":
# Special calculations for BarclayHedgeCTA
results_great_recession.loc[name, 'Total Return'] = qs.stats.comp(subperiod_data_great_recession)
results_great_recession.loc[name, 'Annualized Volatility'] = qs.stats.volatility(subperiod_data_great_recession, periods=12)
results_great_recession.loc[name, 'Sharpe Ratio'] = qs.stats.sharpe(subperiod_data_great_recession, periods=12)
results_great_recession.loc[name, 'Max Drawdown'] = qs.stats.max_drawdown(subperiod_data_great_recession)
results_great_recession.loc[name, 'Sortino Ratio'] = qs.stats.sortino(subperiod_data_great_recession, periods=12)
results_great_recession.loc[name, 'Beta SPY'] = qs.stats.greeks(subperiod_data_great_recession, benchmark=SPY[start_date:end_date])['beta']
else:
# General calculations for all other strategies
results_great_recession.loc[name, 'Total Return'] = qs.stats.comp(subperiod_data_great_recession)
results_great_recession.loc[name, 'Annualized Volatility'] = qs.stats.volatility(subperiod_data_great_recession)
results_great_recession.loc[name, 'Sharpe Ratio'] = qs.stats.sharpe(subperiod_data_great_recession)
results_great_recession.loc[name, 'Max Drawdown'] = qs.stats.max_drawdown(subperiod_data_great_recession)
results_great_recession.loc[name, 'Sortino Ratio'] = qs.stats.sortino(subperiod_data_great_recession)
if name != 'SPY': # Assuming you don't want to calculate beta for SPY against itself
greek = qs.stats.greeks(subperiod_data_great_recession, benchmark=SPY[start_date:end_date])
results_great_recession.loc[name, 'Beta SPY'] = greek['beta']
if name != 'BarclayHedgeCTA': # Assuming you don't want to calculate beta for SPY against itself
greek = qs.stats.greeks(subperiod_data_great_recession, benchmark=BarclayHedgeCTA[start_date:end_date])
results_great_recession.loc[name, 'Beta CTA'] = greek['beta']
# Save results to Excel (optional)
results_great_recession.to_excel('Results_great_recession.xlsx')
# Display the results DataFrame
results_great_recession
<ipython-input-116-7da8a2c97c1c>:52: UserWarning: Pandas requires version '1.4.3' or newer of 'xlsxwriter' (version '1.3.8' currently installed).
| Total Return | Annualized Volatility | Sharpe Ratio | Max Drawdown | Sortino Ratio | Beta CTA | Beta SPY | |
|---|---|---|---|---|---|---|---|
| SPY | -0.381475 | 0.382405 | -0.607081 | -0.552144 | -0.855154 | 0.003185 | NaN |
| BarclayHedgeCTA | 0.143656 | 0.068084 | 1.281422 | -0.030139 | 3.019330 | NaN | -0.055825 |
| SMA EW | 0.323348 | 0.168236 | 1.107603 | -0.175243 | 1.723877 | -0.061198 | -0.235586 |
| SMA with Bands EW | 0.310761 | 0.167973 | 1.074089 | -0.173921 | 1.666428 | -0.060187 | -0.234525 |
| TSMOM EW | 0.098651 | 0.160239 | 0.440829 | -0.198377 | 0.649621 | -0.036016 | -0.235612 |
| RAMOM EW | 0.405536 | 0.156668 | 1.414032 | -0.105063 | 2.193641 | -0.053445 | -0.156208 |
| Kalman EW | -0.066683 | 0.115063 | -0.311241 | -0.137152 | -0.438229 | 0.070349 | 0.054391 |
| SMA VW | 0.203827 | 0.087823 | 1.342277 | -0.100159 | 2.117559 | -0.020346 | -0.119464 |
| SMA with Bands VW | 0.183774 | 0.083544 | 1.283044 | -0.097420 | 1.993653 | -0.026170 | -0.114070 |
| TSMOM VW | 0.097428 | 0.084289 | 0.720027 | -0.109756 | 1.081997 | -0.019333 | -0.125244 |
| RAMOM VW | 0.209940 | 0.081235 | 1.482650 | -0.067923 | 2.321169 | -0.015457 | -0.078345 |
| Kalman VW | -0.055474 | 0.062674 | -0.528380 | -0.103963 | -0.711865 | 0.031790 | 0.032093 |
# Assuming each strategy variable is already defined and holds return data
strategies = {
"SPY": SPY,
"BarclayHedgeCTA": BarclayHedgeCTA,
"SMA EW": portfolio_SMA_simple_returns,
"SMA with Bands EW": portfolio_SMA_bands_simple_returns,
"TSMOM EW": portfolio_TSMOM_simple_returns,
"RAMOM EW": portfolio_RAMOM_simple_returns,
"Kalman EW": portfolio_kalman_simple_returns,
"SMA VW": portfolio_SMA_simple_returns_vol,
"SMA with Bands VW": portfolio_SMA_bands_simple_returns_vol,
"TSMOM VW": portfolio_TSMOM_simple_returns_vol,
"RAMOM VW": portfolio_RAMOM_simple_returns_vol,
"Kalman VW": portfolio_kalman_simple_returns_vol
}
# Create a DataFrame to store the results
results_covid = pd.DataFrame()
# Define subperiod
start_date = '2020-02-01'
end_date = '2020-04-30'
# Calculate metrics for each strategy during the subperiod
for name, data in strategies.items():
# Filter data for the subperiod
subperiod_data_covid = data[start_date:end_date]
if name == "BarclayHedgeCTA":
# Special calculations for BarclayHedgeCTA
results_covid.loc[name, 'Total Return'] = qs.stats.comp(subperiod_data_covid)
results_covid.loc[name, 'Annualized Volatility'] = qs.stats.volatility(subperiod_data_covid, periods=12)
results_covid.loc[name, 'Sharpe Ratio'] = qs.stats.sharpe(subperiod_data_covid, periods=12)
results_covid.loc[name, 'Max Drawdown'] = qs.stats.max_drawdown(subperiod_data_covid)
results_covid.loc[name, 'Sortino Ratio'] = qs.stats.sortino(subperiod_data_covid, periods=12)
results_covid.loc[name, 'Beta SPY'] = qs.stats.greeks(subperiod_data_covid, benchmark=SPY[start_date:end_date])['beta']
else:
# General calculations for all other strategies
results_covid.loc[name, 'Total Return'] = qs.stats.comp(subperiod_data_covid)
results_covid.loc[name, 'Annualized Volatility'] = qs.stats.volatility(subperiod_data_covid)
results_covid.loc[name, 'Sharpe Ratio'] = qs.stats.sharpe(subperiod_data_covid)
results_covid.loc[name, 'Max Drawdown'] = qs.stats.max_drawdown(subperiod_data_covid)
results_covid.loc[name, 'Sortino Ratio'] = qs.stats.sortino(subperiod_data_covid)
if name != 'SPY': # Assuming you don't want to calculate beta for SPY against itself
greek = qs.stats.greeks(subperiod_data_covid, benchmark=SPY[start_date:end_date])
results_covid.loc[name, 'Beta SPY'] = greek['beta']
if name != 'BarclayHedgeCTA': # Assuming you don't want to calculate beta for SPY against itself
greek = qs.stats.greeks(subperiod_data_covid, benchmark=BarclayHedgeCTA[start_date:end_date])
results_covid.loc[name, 'Beta CTA'] = greek['beta']
# Save results to Excel (optional)
results_covid.to_excel('Results_covid.xlsx')
# Display the results DataFrame
results_covid
<ipython-input-117-f160e715ea37>:52: UserWarning: Pandas requires version '1.4.3' or newer of 'xlsxwriter' (version '1.3.8' currently installed).
| Total Return | Annualized Volatility | Sharpe Ratio | Max Drawdown | Sortino Ratio | Beta CTA | Beta SPY | |
|---|---|---|---|---|---|---|---|
| SPY | -0.097131 | 0.597390 | -0.398187 | -0.341047 | -0.545211 | 2.467566 | NaN |
| BarclayHedgeCTA | 0.008523 | 0.045536 | 0.761660 | 0.000000 | 1.846975 | NaN | -0.057977 |
| SMA EW | 0.053253 | 0.433450 | 0.678492 | -0.147487 | 1.180354 | -0.720125 | -0.221315 |
| SMA with Bands EW | 0.054067 | 0.433776 | 0.685325 | -0.146277 | 1.193522 | -0.667976 | -0.221680 |
| TSMOM EW | 0.010314 | 0.420297 | 0.296573 | -0.147434 | 0.504697 | -0.281847 | -0.149386 |
| RAMOM EW | 0.101606 | 0.436384 | 1.083296 | -0.137484 | 1.824874 | -0.429474 | -0.184418 |
| Kalman EW | -0.170667 | 0.415100 | -1.566797 | -0.276783 | -2.113758 | 0.644604 | 0.123475 |
| SMA VW | 0.019074 | 0.070510 | 1.089879 | -0.030092 | 1.928763 | -0.280779 | -0.087152 |
| SMA with Bands VW | 0.019250 | 0.066508 | 1.161626 | -0.025980 | 2.052963 | -0.308394 | -0.082187 |
| TSMOM VW | 0.007634 | 0.056040 | 0.561936 | -0.026269 | 0.852489 | -0.096721 | -0.063279 |
| RAMOM VW | 0.049859 | 0.064282 | 3.013002 | -0.020459 | 5.335903 | -0.252097 | -0.071098 |
| Kalman VW | -0.096492 | 0.066415 | -5.978148 | -0.101195 | -5.832602 | 0.195579 | 0.060143 |